Giter Site home page Giter Site logo

admkopec / lsfilewrapper Goto Github PK

View Code? Open in Web Editor NEW
17.0 1.0 0.0 125 KB

๐Ÿ“ A Swift and Objective-C replacement for NSFileWrapper that loads / saves content on-demand with minimal memory footprint. Understands how to save / serialize objects like NSData, UIImage, NSImage, NSDictionary, etc...

License: MIT License

Objective-C 72.57% Swift 27.43%
nsdocument uidocument nsfilewrapper objective-c macos ios swift filewrapper nsimage uiimage

lsfilewrapper's Introduction

๐Ÿ“ LSFileWrapper

Platforms GitHub Swift Package Manager Build iOS Build macOS

Replacement for NSFileWrapper that loads / saves content on-demand. It is specifically designed to handle large packages / bundles or directories with multiple file entries. It requires minimal memory footprint, as it doesn't try to load everything into memory (unlike Apple's NSFileWrapper), but rather tries to memory map the single files only when they're actively being used. This library also has built-in convenience methods for saving / serializing objects like NSData, UIImage, NSImage, NSDictionary, etc...

๐Ÿ’ป Requirements

LSFileWrapper works on Mac OS X 10.7+ and iOS 8.0 or newer. The Xcode project contains two framework targets for:

  • ๐Ÿ’ป macOS (10.7 or greater)
  • ๐Ÿ“ฑ iOS (8.0 or greater)

๐Ÿ“– Usage

Creating new wrappers

To create a new LSFileWrapper use -initDirectory for directory wrappers or -initFile for regular file wrappers. These wrappers and all of their contents will be stored entirely in the memory until any of the write methods gets called.

LSFileWrapper* newDirectoryWrapper = [[LSFileWrapper alloc] initDirectory];
LSFileWrapper* newRegularFileWrapper = [[LSFileWrapper alloc] initFile];

Swift:

let newDirectoryWrapper = LSFileWrapper(directory: ())
let newRegularFileWrapper = LSFileWrapper(file: ())

Loading from disk

To load an existing wrapper from disk use -initWithURL. When boolean NO is passed to isDirectory, the init method checks and automatically creates correct LSFileWrapper type based on passed url.

NSURL* url;

LSFileWrapper* existingWrapper = [[LSFileWrapper alloc] initWithURL: url isDirectory: NO];

Swift:

let url: URL

let existingWrapper = LSFileWrapper(with: url, isDirectory: false)

Writing to disk

Notice: Writing methods should only be called on the top most wrapper โ€“ a wrapper that has no parents.

To write the wrapper to disk call -writeToURL or -writeUpdatesToURL, the difference between the two being that updates will update the cached wrapper location and remove changes from memory, so use this only in situations like autosave. For duplicate operations use -writeToURL. Only the main wrapper can be written to disk โ€“ the wrapper that has no parents. If the write is issued as part of NSDocument's save routine there's a convenience method -writeToURL forSaveOperation that automatically calls -writeToURL or -writeUpdatesToURL based on save operation and also handles document backups (versioning) and url switches on save as.

LSFileWrapper* mainWrapper;
NSURL* url;

// Saves all contents to disk at specified URL
[mainWrapper writeToURL: url];

// Dumps all changes to the specified URL, make sure that the LSFileWrapper contents are present at the URL, 
// otherwise the write method could result in partial contents on the disk and potential loss of data.
[mainWrapper writeUpdatesToURL: url];

NSDocument (macOS only):

LSFileWrapper* mainWrapper;

-(BOOL)writeToURL:(NSURL *)url forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError __autoreleasing *)outError {
    [url startAccessingSecurityScopedResource]; // Recommended on OS X 10.7.3 and newer
    BOOL success = [mainWrapper writeToURL: url forSaveOperation: saveOperation originalContentsURL: absoluteOriginalContentsURL backupDocumnetURL: [self backupFileURL] outError: outError];
    [url stopAccessingSecurityScopedResource];
    return success;
}

Swift:

let mainWrapper: LSFileWrapper
let url: URL

// Saves all contents to disk at specified URL
mainWrapper.write(to: url)

// Dumps all changes to the specified URL, make sure that the LSFileWrapper contents are present at the URL, 
// otherwise the write method could result in partial contents on the disk and potential loss of data.
mainWrapper.writeUpdates(to: url)

NSDocument (macOS only):

let mainWrapper: LSFileWrapper

override func write(to url: URL, for saveOperation: SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws {
    _ = url.startAccessingSecurityScopedResource()
    try mainPackageWrapper.write(to: url, for: saveOperation, originalContentsURL: absoluteOriginalContentsURL, backupDocumentURL: self.backupFileURL)
    url.stopAccessingSecurityScopedResource()
}

Adding contents

Notice: Directory wrappers only.

To add a file wrapper to an existing directory wrapper use -addFileWrapper or -setFileWrapper, the difference between the two being that add will suffix a filename with 2, 3, 4, etcโ€ฆ if the wrapper with the same name already exists and return the final filename, set will overwrite any existing file wrappers. -addContent and -setContent work the same way, but create the file wrapper for you.

LSFileWrapper* directoryWrapper;

// Adds an empty directory with preferred name
NSString* folderName = [directoryWrapper addFileWrapper: [[LSFileWrapper alloc] initDirectory] withFilename: @"Empty Directory Name"];

// Adds and overrides any wrappers matching the filename
[directoryWrapper setFileWrapper: [[LSFileWrapper alloc] initDirectory] withFilename: @"Empty Directory Name"];

// Adds a new text file
NSString* fileName = [directoryWrapper addContent: @"Hello, World!" withFilename: @"hello.txt"];

// Adds and overrides any files matching the filename. This method could also be used when changes are made to the file
[directoryWrapper setContent: @"Hello, World!" withFilename: @"hello.txt"];

Swift:

let directoryWrapper: LSFileWrapper

// Adds an empty directory with preferred name
let folderName = directoryWrapper.add(wrapper: LSFileWrapper(directory: ()) withFilename: "Empty Directory Name")

// Adds and overrides any wrappers matching the filename
directoryWrapper.set(wrapper: LSFileWrapper(directory: ()) withFilename: "Empty Directory Name")

// Adds a new text file. Content has to be of Objective-C type, i.e. NSString, NSData... or casted with `as` operator
let filename = directoryWrapper.add(content: NSString("Hello, World!"), withFilename: "hello.txt")

// Adds and overrides any files matching the filename. This method can be used when changes are made to the file
directoryWrapper.set(content: "Hello, World!" as NSString, withFilename: "hello.txt")

Reading Contents

Notice: File wrappers only.

To retrieve contents of a regular file wrapper use one of various convenience methods: -data, -string, -dictionary, -image.

LSFileWrapper* fileWrapper;

NSData* data = [fileWrapper data];
NSString* string = [fileWrapper string];

Swift:

let fileWrapper: LSFileWrapper

let optionalData = fileWrapper.data()
let optionalString = fileWrapper.string()

Updating Contents

Notice: File wrappers only.

To update the contents of a regular file wrapper use -updateContent, named update(newContent:) in Swift.

LSFileWrapper* fileWrapper;

[fileWrapper updateContent: @"Hello, World!"];

Swift:

let fileWrapper: LSFileWrapper

fileWrapper.update(newContent: "Hello, World!" as NSString)

Removing wrappers

Notice: Directory wrappers only.

To remove a file wrapper from existing wrapper use -removeFileWrapper or removeFileWrapperWithPath, named removeWrapper() or removeWrapper(with:) in Swift.

LSFileWrapper* directoryWrapper;

// Using a path, can also contain "/" for subfolder search, all children can be removed
[directoryWrapper removeFileWrapperWithPath: @"hello.txt"];

// Using an instance of a wrapper. Path can also contain "/" for subfolder search, however only 'first' children can be removed.
LSFileWrapper* wrapperToRemove = [directoryWrapper fileWrapperWithPath: @"hello.txt"];
if (wrapperToRemove) {
    [directoryWrapper removeFileWrapper: wrapperToRemove];
}

Swift:

let directoryWrapper: LSFileWrapper

// Using a path, can also contain "/" for subfolder search, all children can be removed
directoryWrapper.removeWrapper(with: "hello.txt")

// Using an instance of a wrapper. Path can also contain "/" for subfolder search, however only 'first' children can be removed.
if let wrapperToRemove = directoryWrapper.wrapper(with: "hello.txt") {
    directoryWrapper.removeWrapper(wrapperToRemove)
}

Getting child wrappers

Notice: Directory wrappers only.

To get a wrapper from a directory wrapper call -fileWrapperWithPath, named wrappers(with:) in Swift, this will also traverse all children based on supplied path.

LSFileWrapper* directoryWrapper;

LSFileWrapper* wrapper = [directoryWrapper fileWrapperWithPath: @"hello.txt"];

Swift:

let directoryWrapper: LSFileWrapper

let wrapper = directoryWrapper.wrapper(with: "hello.txt")

To get all first-degree child wrappers from a directory wrapper call -fileWrappersInPath, named wrappers(in:) in Swift, this will also traverse all children based on supplied path.

LSFileWrapper* directoryWrapper;

NSArray<LSFileWrapper*> *wrappers = [directoryWrapper fileWrappersInPath: @"/"];

Swift:

let directoryWrapper: LSFileWrapper

let wrappers = directoryWrapper.wrappers(in: "/")

โš–๏ธ License

LSFileWrapper is distributed under the MIT license.

lsfilewrapper's People

Contributors

admkopec avatar lukescott avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.