© Jesse Feiler 2019
Jesse FeilerImplementing iOS and macOS Documents with the Files Apphttps://doi.org/10.1007/978-1-4842-4492-0_10

10. Working with File Wrappers and Packages

Jesse Feiler1 
(1)
Plattsburgh, NY, USA
 

This section lets you look at data storage tools other than documents. Like documents, they are all ways to persist data from your apps, and all of these tools, including documents, are supported on Cocoa and Cocoa Touch. Many of the tools (including the ones in this part of the book) have long histories in Cocoa and its predecessors. As noted, documents have evolved over time and have changed in many ways. The tools in this section have certainly changed over time, but the basic structures have remained remarkably stable so they are used in many legacy apps as well as in ones being developed today.

All of the tools in this chapter let you combine files into multi-file structures that can be manipulated either as single structures or as their component parts.

Using Packages

From early days of Macintosh, multi-file packages have been used to manage files. In the first Macintosh file system , files had two sections called forks. Almost all files had a data fork, and many files also had a resource fork. The user-visible file was basically the data fork, and the resource fork contained elements that the data fork used. These elements were typically alerts, icons, and other identifiable or visible elements. Each type of element in a resource fork had a name, typically a four-character code such as ALRT (for alert), DLOG (for dialog), or ICON. The idea of using identifiable and structured elements in a container remains a critical part of Cocoa.

The disadvantage of the resource fork was that when you copied a file to another platform the resource fork typically disappeared; it was the data fork that contained the data so it wasn’t a disaster in most cases. Today, Cocoa (and Cocoa Touch) use a more sophisticated way of wrapping data into what appears to be a single file. They are referred to as packages.

Note

Swift packages are manifests that are used to assemble code and manage dependencies. A common tool is CocoaPods ( CocoaPods.org ).

You can still see packages throughout Cocoa and particularly in the developer tools. When you create a project in Xcode, you usually create a folder that contains two items, shown in Figure 10-1.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig1_HTML.jpg
Figure 10-1

An Xcode project consists of a file and a folder

In the example shown in Figure 10-1, the name of the project is iOSDocumentApp. The project itself is in an xcodeproj file, which contains references to the iOSDocumentApp folder. The open folder is shown in Figure 10-2. Note that inside the folder are individual files as well as subfolders with more files and folders.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig2_HTML.jpg
Figure 10-2

The project folder contains subfolders and files

If you hold down Control while clicking a file or folder in the Finder, you will see the contents of that file or folder as a package. This is shown in Figure 10-3.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig3_HTML.jpg
Figure 10-3

Use the Control key to look inside a file package

Note that not all files or folders are packages, so the Control key cannot open them. However, it is important to note that your Xcode project is a package of files. If you move the folder away from the xcodeproj file that refers to it, you will break the project package.

Inside a file package, the contents are often structured with a Contents folder that contains subfolders, as you can see in Figure 10-4. Most apps have a Contents folder.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig4_HTML.jpg
Figure 10-4

Files and folders can be structured within the package

Considering Bundles

If you look at build phases in an Xcode app, you’ll see a step that moves files into an app bundle, as shown in Figure 10-5.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig5_HTML.jpg
Figure 10-5

Apps contain bundles

When you add files to an app in the project navigator, they are usually automatically added to the Build Phases step so that they are found in the app bundle, and that’s where you can retrieve them from in your code. By default, your app has a main bundle (bundle.main) with known contents. You can find the API at developer.apple.com by looking for bundle.

Using File Wrappers

File wrappers are somewhat similar to packages in that they may contain files and folders inside a single object. A file wrapper typically has at least one file, but it can be empty. File wrappers are most frequently used as the container for files and folders in a document that itself is a file wrapper. Figure 10-6 shows a file wrapper document.
../images/465467_1_En_10_Chapter/465467_1_En_10_Fig6_HTML.jpg
Figure 10-6

Declaring a file wrapper document

Note that you need to set the LSTypeIsPackage property to YES so that the document appears to the user as a single object. The file type should conform to com.apple.package.

You can download WrapperPlaygroundDemo as described in Chapter 1 to see how to put a file wrapper document together. The process is described in the following section. The code is shown in Listing 10-1.

The process is simple:
  • Assemble the files that will be wrapped.

  • Convert each file to the Data type (formerly NSData). There are utility methods in Swift to do this easily.

  • Wrap each file in a wrapper.

  • Create a root wrapper in the document.

  • Add each wrapped file to the root wrapper.

You can do these steps in any order, and there are functions that let you add and remove them dynamically. One common use of file wrappers is to wrap together several related files such as media and text. If they are wrapped in a file wrapper, you use the contents(forType:) and load(fromContents:ofType:) methods as you would for a document that consists of any data type such as an archive or a single image or text.

The files in the root file wrapper are not in any given order. Most important for reasons of efficiency is the fact that each file wrapper is loaded separately so if you have a lot of files in a single object, you can load them on an as-needed basis (Swift and Cocoa take care of this for you).

Listing 10-1 shows the code to assemble a file wrapper from files named testString and testImage; they are each wrapped in an individual wrapper (the names are stringDataWrapper and imageDataWrapper). In addition, there is a rootDirectoryWrapper. As noted in the code at the end of Listing 10-1, you can read or write the wrapped files using contents(forType:) or load(fromContents:ofType:) .
import UIKit
import PlaygroundSupport
let testString = "Now is the time"
let testImage = UIImage(named:"mantegna.jpg")
// convert to Data
let imageData = testImage!.pngData()
let stringData = testString.data (using: .utf8)
// build directory wrapper
let rootDirectoryWrapper = FileWrapper(directoryWithFileWrappers: [:])
// wrap string
let stringDataWrapper = FileWrapper(regularFileWithContents: stringData!)
stringDataWrapper.preferredFilename = "StringWrapper"
rootDirectoryWrapper.addFileWrapper(stringDataWrapper)
// wrap image
let imageDataWrapper = FileWrapper(regularFileWithContents: imageData!)
imageDataWrapper.preferredFilename = "ImageWrapper"
rootDirectoryWrapper.addFileWrapper(imageDataWrapper)
print ("wrapper", rootDirectoryWrapper)
print (rootDirectoryWrapper.fileWrappers)
for eachWrapper in rootDirectoryWrapper.fileWrappers! {
  print (eachWrapper)
}
// for writing: return rootDirectoryWrapper if you are using in contents(forType:)
// for reading: load(fromContents:ofType:)
Listing 10-1

Assembling a File Wrapper Document in a Playground

Summary

This chapter showed how to wrap files together in bundles or file wrappers. There are efficiencies to using file wrappers since only necessary file wrappers are updated as the root file wrapper is managed. The overall idea of having a way to handle files separately or together depending on what you want to do with them is the key take-away from wrappers and bundles.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.189.247