SlideShare a Scribd company logo
1 of 59
Download to read offline
CS193p

Fall 2017-18
Stanford CS193p
Developing Applications for iOS

Fall 2017-18
CS193p

Fall 2017-18
Today
Emoji Art
Demo continued ā€¦ UITextField to add more Emoji
Persistence
UserDefaults
Property List
Archiving and Codable
Filesystem
Core Data
Cloud Kit
UIDocument
UIDocumentBrowserViewController
CS193p

Fall 2017-18
UserDefaults
A very lightweight and limited database
UserDefaults is essentially a very tiny database that persists between launchings of your app.
Great for things like ā€œsettingsā€ and such. Do not use it for anything big!
What can you store there?
You are limited in what you can store in UserDefaults: it only stores Property List data.
A Property List is any combo of Array, Dictionary, String, Date, Data or a number (Int, etc.).
This is an old Objective-C API with no type that represents all those, so this API uses Any.
If this were a new, Swift-style API, it would almost certainly not use Any.
(Likely there would be a protocol or some such that those types would implement.)
What does the API look like?
Itā€™s ā€œcoreā€ functionality is simple. It just stores and retrieves Property Lists by key ā€¦
func set(Any?, forKey: String) // the Any has to be a Property List (or crash)
func object(forKey: String) -> Any? // the Any is guaranteed to be a Property List
CS193p

Fall 2017-18
UserDefaults
Reading and Writing
You donā€™t usually create one of these databases with UserDefaults().
Instead, you use the static (type) var called standard ā€¦
let defaults = UserDefaults.standard
Setting a value in the database is easy since the set method takes an Any?.
defaults.set(3.1415, forKey: ā€œpiā€) // 3.1415 is a Double which is a Property List type
defaults.set([1,2,3,4,5], forKey: ā€œMy Arrayā€) // Array and Int are both Property Lists
defaults.set(nil, forKey: ā€œSome Settingā€) // removes any data at that key
You can pass anything as the ļ¬rst argument as long as itā€™s a combo of Property List types.
UserDefaults also has convenience API for getting many of the Property List types.
func double(forKey: String) -> Double
func array(forKey: String) -> [Any]? // returns nil if non-Array at that key
func dictionary(forKey: String) -> [String:Any]? // note that keys in return are Strings
The Any in the returned values will, of course, be a Property List type.
CS193p

Fall 2017-18
UserDefaults
Saving the database
Your changes will be occasionally autosaved.
But you can force them to be saved at any time with synchronize ā€¦
if !defaults.synchronize() { // failed! but not clear what you can do about it }
(itā€™s not ā€œfreeā€ to synchronize, but itā€™s not that expensive either)
CS193p

Fall 2017-18
Archiving
There are two mechanisms for making ANY object persistent
A historical method which is how, for example, the storyboard is made persistent.
A new mechanism in iOS 11 which is supported directly by the Swift language environment.
Weā€™re only going to talk in detail about the second of these.
Since itā€™s supported by the language, itā€™s much more likely to be the one youā€™d use.
CS193p

Fall 2017-18
Archiving
NSCoder (old) mechanism
Requires all objects in an object graph to implement these two methods ā€¦
func encode(with aCoder: NSCoder)
init(coder: NSCoder)
Essentially you store all of your objectā€™s data in the coderā€™s dictionary.
Then you have to be able to initialize your object from a coderā€™s dictionary.
References within the object graph are handled automatically.
You can then take an object graph and turn it into a Data (via NSKeyedArchiver).
And then turn a Data back into an object graph (via NSKeyedUnarchiver).
Once you have a Data, you can easily write it to a ļ¬le or otherwise pass it around.
CS193p

Fall 2017-18
Archiving
Codable (new) mechanism
Also is essentially a way to store all the vars of an object into a dictionary.
To do this, all the objects in the graph of objects you want to store must implement Codable.
But the difference is that, for standard Swift types, Swift will do this for you.
If you have non-standard types, you can do something similar to the old method.
Some of the standard types (that youā€™d recognize) that are automatically Codable by Swift ā€¦
String, Bool, Int, Double, Float
Optional
Array, Dictionary, Set, Data
URL
Date, DateComponents, DateInterval, Calendar
CGFloat, AffineTransform, CGPoint, CGSize, CGRect, CGVector
IndexPath, IndexSet
NSRange
CS193p

Fall 2017-18
Archiving
Codable (new) mechanism
Once your object graph is all Codable, you can convert it to either JSON or a Property List.
let object: MyType = ā€¦
let jsonData: Data? = try? JSONEncoder().encode(object)
Note that this encode throws. You can catch and ļ¬nd errors easily (next slide).
By the way, you can make a String object out of this Data like this ā€¦
let jsonString = String(data: jsonData!, encoding: .utf8) // JSON is always utf8
To get your object graph back from the JSON ā€¦
if let myObject: MyType = try? JSONDecoder().decode(MyType.self, from: jsonData!) {
}
JSON is not ā€œstrongly typed.ā€ So things like Date or URL are just strings.
Swift handles all this automatically and is even conļ¬gurable, for example ā€¦
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601 // or .secondsSince1970, etc.
CS193p

Fall 2017-18
Archiving
Codable (new) mechanism
Hereā€™s what it might look like to catch errors during a decoding.
The thing decode throws is an enum of type DecodingError.
Note how we can get the associated values of the enum similar to how we do with switch.
do {
let object = try JSONDecoder().decode(MyType.self, from: jsonData!)
// success, do something with object
} catch DecodingError.keyNotFound(let key, let context) {
print(ā€œcouldnā€™t find key (key) in JSON: (context.debugDescription)ā€)
} catch DecodingError.valueNotFound(let type, let context) {
} catch DecodingError.typeMismatch(let type, let context) {
} catch DecodingError.dataCorrupted(let context) {
}
CS193p

Fall 2017-18
Archiving
Codable Example
So how do you make your data types Codable? Usually you just say so ā€¦
struct MyType : Codable {
var someDate: Date
var someString: String
var other: SomeOtherType // SomeOtherType has to be Codable too!
}
If your vars are all also Codable (standard types all are), then youā€™re done!
The JSON for this might look like ..
{
ā€œsomeDateā€ : ā€œ2017-11-05T16:30:00Zā€,
ā€œsomeStringā€ : ā€œHelloā€,
ā€œotherā€ : <whatever SomeOtherType looks like in JSON>
}
CS193p

Fall 2017-18
Archiving
Codable Example
Sometimes JSON keys might have different names than your var names (or not be included).
For example, someDate might be some_date.
You can conļ¬gure this by adding a private enum to your type called CodingKeys like this ā€¦
struct MyType : Codable {
var someDate: Date
var someString: String
var other: SomeOtherType // SomeOtherType has to be Codable too!
private enum CodingKeys : String, CodingKey {
case someDate = ā€œsome_dateā€
// note that the someString var will now not be included in the JSON
case other // this key is also called ā€œotherā€ in JSON
}
}
CS193p

Fall 2017-18
Archiving
Codable Example
You can participate directly in the decoding by implementing the decoding initializer ā€¦
struct MyType : Codable {
var someDate: Date
var someString: String
var other: SomeOtherType // SomeOtherType has to be Codable too!
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
someDate = try container.decode(Date.self, forKey: .someDate)
// process rest of vars, perhaps validating input, etc. ā€¦
}
}
Note that this init throws, so we donā€™t need do { } inside it (it will just rethrow).
Also note the ā€œkeysā€ are from the CodingKeys enum on the previous slide (e.g. .someDate).
CS193p

Fall 2017-18
Archiving
Codable Example
You can participate directly in the decoding by implementing the decoding initializer ā€¦
class MyType : Codable {
var someDate: Date
var someString: String
var other: SomeOtherType // SomeOtherType has to be Codable too!
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
someDate = try container.decode(Date.self, forKey: .someDate)
// process rest of vars, perhaps validating input, etc. ā€¦
let superDecoder = try container.superDecoder()
try super.init(from: superDecoder) // only if class
}
}
Donā€™t call super.init with your own decoder (use your containerā€™s superDecoder()).
CS193p

Fall 2017-18
Archiving
Codable Example
You can participate directly in the decoding by implementing the decoding initializer ā€¦
struct MyType : Codable {
var someDate: Date
var someString: String
var other: SomeOtherType // SomeOtherType has to be Codable too!
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
// there are other containers too (e.g. an unkeyed (i.e. array) container) ā€¦
try container.encode(someDate, forKey: .someDate)
// encode the rest of vars, perhaps transforming them, etc. ā€¦
}
}
CS193p

Fall 2017-18
File System
Your application sees iOS ļ¬le system like a normal Unix ļ¬lesystem
It starts at /.
There are ļ¬le protections, of course, like normal Unix, so you canā€™t see everything.
In fact, you can only read and write in your applicationā€™s ā€œsandboxā€.
Why sandbox?
Security (so no one else can damage your application)
Privacy (so no other applications can view your applicationā€™s data)
Cleanup (when you delete an application, everything it has ever written goes with it)
So whatā€™s in this ā€œsandboxā€?
Application directory ā€” Your executable, .storyboards, .jpgs, etc.; not writeable.
Documents directory ā€” Permanent storage created by and always visible to the user.
Application Support directory ā€” Permanent storage not seen directly by the user.
Caches directory ā€” Store temporary ļ¬les here (this is not backed up by iTunes).
Other directories (see documentation) ā€¦
CS193p

Fall 2017-18
File System
Getting a path to these special sandbox directories
FileManager (along with URL) is what you use to ļ¬nd out about whatā€™s in the ļ¬le system.
You can, for example, ļ¬nd the URL to these special system directories like this ...
let url: URL = FileManager.default.url(
for directory: FileManager.SearchPathDirectory.documentDirectory, // for example
in domainMask: .userDomainMask // always .userDomainMask on iOS
appropriateFor: nil, // only meaningful for ā€œreplaceā€ ļ¬le operations
create: true // whether to create the system directory if it doesnā€™t already exist
)
Examples of SearchPathDirectory values
.documentDirectory, .applicationSupportDirectory, .cachesDirectory, etc.
CS193p

Fall 2017-18
URL
Building on top of these system paths
URL methods:
func appendingPathComponent(String) -> URL
func appendingPathExtension(String) -> URL // e.g. ā€œjpgā€
Finding out about whatā€™s at the other end of a URL
var isFileURL: Bool // is this a ļ¬le URL (whether ļ¬le exists or not) or something else?
func resourceValues(for keys: [URLResourceKey]) throws -> [URLResourceKey:Any]?
Example keys: .creationDateKey, .isDirectoryKey, .fileSizeKey
CS193p

Fall 2017-18
File System
Data
Reading binary data from a URL ā€¦
init(contentsOf: URL, options: Data.ReadingOptions) throws
Writing binary data to a URL ā€¦
func write(to url: URL, options: Data.WritingOptions) throws -> Bool
The options can be things like .atomic (write to tmp ļ¬le, then swap) or .withoutOverwriting.
Notice that this function throws.
CS193p

Fall 2017-18
File System
FileManager
Provides utility operations.
e.g., fileExists(atPath: String) -> Bool
Can create and enumerate directories; move, copy, delete ļ¬les; etc.
Thread safe (as long as a given instance is only ever used in one thread).
Also has a delegate with lots of ā€œshouldā€ methods (to do an operation or proceed after an error).
And plenty more. Check out the documentation.
CS193p

Fall 2017-18
Core Data
Database
Sometimes you need to store large amounts of data locally in a database.
And you need to search through it in an efļ¬cient, sophisticated manner.
Enter Core Data
Object-oriented database.
Very, very powerful framework in iOS (unfortunately no time to cover it this quarter).
Check out Winter of 2016-17ā€™s iTunesU for a full pair of lectures on it!
Itā€™s a way of creating an object graph backed by a database
Usually backed by SQL (but also can do XML or just in memory).
How does it work?
Create a visual mapping (using Xcode tool) between database and objects.
Create and query for objects using object-oriented API.
Access the ā€œcolumns in the database tableā€ using vars on those objects.
CS193p

Fall 2017-18
Hereā€™s what the graphical database
schema editor looks like.
CS193p

Fall 2017-18
Core Data
So how do you access all of this stuff in your code?
Core Data is access via an NSManagedObjectContext.
It is the hub around which all Core Data activity turns.
The code that the Use Core Data button adds creates one for you in your AppDelegate.
CS193p

Fall 2017-18
Core Data
What does it look like to create/update objects in the database?
It looks a lot like accessing normal Swift objects ā€¦
let context: NSManagedObjectContext = ...
if let tweet = Tweet(context: context) {
tweet.text = ā€œ140 characters of pure joyā€
tweet.created = Date()
let joe = TwitterUser(context: tweet.managedObjectContext)
tweet.tweeter = joe
tweet.tweeter.name = ā€œJoe Schmoā€
}
CS193p

Fall 2017-18
Core Data
Deleting objects
context.delete(tweet)
Saving changes
You must explicitly save any changes to a context, but note that this throws.
do {
try context.save()
} catch {
// deal with error
}
However, we usually use a UIManagedDocument which autosaves for us.
More on UIDocument-based code in a few slides ā€¦
CS193p

Fall 2017-18
Querying
Searching for objects in the database
Letā€™s say we want to query for all TwitterUsers ...
let request: NSFetchRequest<TwitterUser> = TwitterUser.fetchRequest()
... who have created a tweet in the last 24 hours ...
let yesterday = Date(timeIntervalSinceNow:-24*60*60) as NSDate
request.predicate = NSPredicate(format: ā€œany tweets.created > %@ā€, yesterday)
... sorted by the TwitterUserā€™s name ...
request.sortDescriptors = [NSSortDescriptor(key: ā€œnameā€, ascending: true)]
let context: NSManagedObjectContext = ...
let recentTweeters = try? context.fetch(request)
Returns an empty Array (not nil) if it succeeds and there are no matches in the database.
Returns an Array of NSManagedObjects (or subclasses thereof) if there were any matches.
And obviously the try fails if the fetch fails.
CS193p

Fall 2017-18
Core Data
And so much more!
Very efļ¬cient
Support for multithreading
Close integration with UITableView (for obvious reasons)
Optimistic locking (deleteConflictsForObject)
Rolling back unsaved changes
Undo/Redo
Staleness (how long after a fetch until a refetch of an object is required?)
Etc., etc. ā€¦
CS193p

Fall 2017-18
Cloud Kit
Cloud Kit
A database in the cloud. Simple to use, but with very basic ā€œdatabaseā€ operations.
Since itā€™s on the network, accessing the database could be slow or even impossible.
This requires some thoughtful programming.
No time for this one either this quarter, but check Spring of 2015-16ā€™s iTunesU for full demo.
Important Components
Record Type - like a class or struct
Fields - like vars in a class or struct
Record - an ā€œinstanceā€ of a Record Type
Reference - a ā€œpointerā€ to another Record
Database - a place where Records are stored
Zone - a sub-area of a Database
Container - collection of Databases
Query - an Database search
Subscription - a ā€œstanding Queryā€ which sends push notiļ¬cations when changes occur
CS193p

Fall 2017-18
Cloud Kit
You must enable iCloud in your Project Settings
Under Capabilities tab, turn on iCloud (On/Off switch).
CS193p

Fall 2017-18
Cloud Kit
You must enable iCloud in your Project Settings
Under Capabilities tab, turn on iCloud (On/Off switch).
Then, choose CloudKit from the Services.
CS193p

Fall 2017-18
Cloud Kit
You must enable iCloud in your Project Settings
Under Capabilities tab, turn on iCloud (On/Off switch).
Then, choose CloudKit from the Services.
Youā€™ll also see a CloudKit Dashboard button which will take you to the Cloud Kit Dashboard.
CS193p

Fall 2017-18
Cloud Kit
Cloud Kit Dashboard
A web-based UI to look at everything you are storing.
Shows you all your Record Types and Fields as well as the data in Records.
You can add new Record Types and Fields and also turn on/off indexes for various Fields.
CS193p

Fall 2017-18
Cloud Kit
Dynamic Schema Creation
But you donā€™t have to create your schema in the Dashboard.
You can create it ā€œorganicallyā€ by simply creating and storing things in the database.
When you store a record with a new, never-before-seen Record Type, it will create that type.
Or if you add a Field to a Record, it will automatically create a Field for it in the database.
This only works during Development, not once you deploy to your users.
CS193p

Fall 2017-18
Cloud Kit
What it looks like to create a record in a database
let db = CKContainer.default.publicCloudDatabase
let tweet = CKRecord(ā€œTweetā€)
tweet[ā€œtextā€] = ā€œ140 characters of pure joyā€
let tweeter = CKRecord(ā€œTwitterUserā€)
tweet[ā€œtweeterā€] = CKReference(record: tweeter, action: .deleteSelf)
db.save(tweet) { (savedRecord: CKRecord?, error: NSError?) -> Void in
if error == nil {
// hooray!
} else if error?.errorCode == CKErrorCode.NotAuthenticated.rawValue {
// tell user he or she has to be logged in to iCloud for this to work!
} else {
// report other errors (there are 29 different CKErrorCodes!)
}
}
CS193p

Fall 2017-18
Cloud Kit
What it looks like to query for records in a database
let db = CKContainer.default.publicCloudDatabase
let predicate = NSPredicate(format: ā€œtext contains %@ā€œ, searchString)
let query = CKQuery(recordType: ā€œTweetā€, predicate: predicate)
db.perform(query) { (records: [CKRecord]?, error: NSError?) in
if error == nil {
// records will be an array of matching CKRecords
} else if error?.errorCode == CKErrorCode.NotAuthenticated.rawValue {
// tell user he or she has to be logged in to iCloud for this to work!
} else {
// report other errors (there are 29 different CKErrorCodes!)
}
}
CS193p

Fall 2017-18
Cloud Kit
Standing Queries (aka Subscriptions)
One of the coolest features of Cloud Kit is its ability to send push notiļ¬cations on changes.
All you do is register an NSPredicate and whenever the database changes to match it, boom!
Unfortunately, we donā€™t have time to discuss push notiļ¬cations this quarter.
If youā€™re interested, check out the UserNotifications framework.
CS193p

Fall 2017-18
UIDocument
When to use UIDocument
If your application stores user information in a way the user perceives as a ā€œdocumentā€.
If you just want iOS to manage the primary storage of user information.
What does UIDocument do?
Manages all interaction with storage devices (not just ļ¬lesystem, but also iCloud, Box, etc.).
Provides asynchronous opening, writing, reading and closing of ļ¬les.
Autosaves your document data.
Makes integration with iOS 11ā€™s new Files application essentially free.
What do you need to do to make UIDocument work?
Subclass UIDocument to add vars to hold the Model of your MVC that shows your ā€œdocumentā€.
Then implement one method that writes the Model to a Data and one that reads it from a Data.
Thatā€™s it.
Now you can use UIDocumentā€™s opening, saving and closing methods as needed.
You can also use its ā€œdocument has changedā€ method (or implement undo) to get autosaving.
CS193p

Fall 2017-18
UIDocument
Subclassing UIDocument
For simple documents, thereā€™s nothing to do here except add your Model as a var ā€¦
class EmojiArtDocument: UIDocument {
var emojiArt: EmojiArt?
}
There are, of course, methods you can override, but usually you donā€™t need to.
Creating a UIDocument
Figure out where you want your document to be stored in the ļ¬lesystem ā€¦
var url = FileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
url = url.appendingPathComponent(ā€œUntitled.fooā€)
Instantiate your subclass by passing that url to UIDocumentā€™s only initializer ā€¦
let myDocument = EmojiArtDocument(fileURL: url)
ā€¦ then (eventually) set your Model var(s) on your newly created UIDocument subclass ā€¦
myDocument.emojiArt = ā€¦
CS193p

Fall 2017-18
UIDocument
Creating a Data for your Model
Override this method in your UIDocument subclass to convert your Model into a Data.
override func contents(forType typeName: String) throws -> Any {
return emojiArt converted into a Data
}
Note that the return type is Any ā€¦ thatā€™s because your ļ¬le format can also be a FileWrapper.
A FileWrapper represents a directory full of ļ¬les that make up your document.
If for some reason you canā€™t create a Data or FileWrapper, you can throw an error here.
Weā€™ll see where that thrown error ends up in a couple of slides.
The forType is a UTI (type identiļ¬er) calculated from your fileURLā€™s ļ¬le extension (e.g. .jpg)
Weā€™ll see in a few slides how to declare what sorts of ļ¬les (the UTIs) your app deals with.
CS193p

Fall 2017-18
UIDocument
Turning a Data into a Model
Override this method in your UIDocument subclass to a Data into an instance of your Model.
override func load(fromContents contents: Any, ofType typeName: String?) throws {
emojiArt = contents converted into an EmojiArt
}
Again, you can throw here if you canā€™t create a document from the passed contents.
CS193p

Fall 2017-18
UIDocument
Ready to go!
Now you can open your document (i.e. get your Model) ā€¦
myDocument.open { success in
if success {
// your Model var(s) (e.g. emojiArt) is/are ready to use
} else {
// there was a problem, check documentState
}
}
This method is asynchronous!
The closure is called on the same thread you call open from (the main thread usually).
Weā€™ll see more about documentState in a couple of slides.
CS193p

Fall 2017-18
UIDocument
Saving your document
You can let your document know that the Model has changed with this method ā€¦
myDocument.updateChangeCount(.done)
ā€¦ or you can use UIDocumentā€™s undoManager (no time to cover that, unfortunately!)
UIDocument will save your changes automatically at the next best opportunity.
Or you can force a save using this method ā€¦
let url = myDocument.fileURL // or something else if you want ā€œsave asā€
myDocument.save(to url: URL, for: UIDocumentSaveOperation) { success in
if success {
// your Model has successfully been saved
} else {
// there was a problem, check documentState
}
}
UIDocumentSaveOperation is either .forCreating or .forOverwriting.
CS193p

Fall 2017-18
UIDocument
Closing your document
When you are ļ¬nished using a document for now, close it ā€¦
myDocument.close { success in
if success {
// your Model has successfully been saved and closed
// use the open method again if you want to use it
} else {
// there was a problem, check documentState
}
}
CS193p

Fall 2017-18
UIDocument
Document State
As all this goes on, your document transitions to various states.
You can ļ¬nd out what state it is in using this var ā€¦
var documentState: UIDocumentState
Possible values ā€¦
.normal ā€” document is open and ready for use!
.closed ā€” document is closed and must be opened to be used
.savingError ā€” document couldnā€™t be saved (override handleError if you want to know why)
.editingDisabled ā€” the document cannot currently be edited (so donā€™t let your UI do that)
.progressAvailable ā€” how far a large document is in getting loaded (check progress var)
.inConflict ā€” someone edited this document somewhere else (iCloud)
To resolve conļ¬‚icts, you access the conļ¬‚icting versions with ā€¦
NSFileVersion.unresolvedConflictVersionsOfItem(at url: URL) -> [NSFileVersion]?
For the best UI, you could give your user the choice of which version to use.
Or, if your documentā€™s contents are ā€œmergeableā€, you could even do that.
documentState can be ā€œobservedā€ using the UIDocumentStateChanged notiļ¬cation (more later).
CS193p

Fall 2017-18
UIDocument
Thumbnail
You can specify a thumbnail image for your UIDocument.
It can make it much easier for users to ļ¬nd the document they want in Files, for example.
Essentially you are going to override the UIDocument method which sets ļ¬le attributes.
The attributes are returned as a dictionary.
One of the keys is for the thumbnail (itā€™s a convoluted key) ā€¦
override func fileAttributesToWrite(to url: URL, for operation: UIDocumentSaveOperation)
throws -> [AnyHashable : Any] {
var attributes = try super.fileAttributesToWrite(to: url, for: saveOperation)
if let thumbnail: UIImage = ā€¦ {
attributes[URLResourceKey.thumbnailDictionaryKey] =
[URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey:thumbnail]
}
return attributes
}
It does not have to be 1024x1024 (it seems to have a minimum size, not sure what).
CS193p

Fall 2017-18
UIDocument
Other
var localizedName: String
var hasUnsavedChanges: Bool
var fileModificationDate: Date?
var userActivity: NSUserActivity? // iCloud documents only
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Managing user documents
You probably want users to be able to easily manage their documents in a document-based app.
Choosing ļ¬les to open, renaming ļ¬les, moving them, accessing iCloud drive, etc.
The UIDocumentBrowserViewController (UIDBVC) does all of this for you.
Using UIDocument to store your document makes leveraging this UIDBVC easy.
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Managing user documents
You probably want users to be able to easily manage their documents in a document-based app.
Choosing ļ¬les to open, renaming ļ¬les, moving them, accessing iCloud drive, etc.
The UIDocumentBrowserViewController (UIDBVC) does all of this for you.
Using UIDocument to store your document makes leveraging this UIDBVC easy.
Using the UIDocumentBrowserViewController
It has to be the root view controller in your storyboard (i.e. the arrow points to it).
Your document-editing MVC will then be presented modally on top of (i.e. takes over the screen).
CS193p

Fall 2017-18
UIDocumentBrowserViewController
What document types can you open?
To use the UIDBVC, you have to register which types your application uses.
You do this in the Project Settings in the Info tab with your Target selected.
In the Document Types area, add the types you support.
Hereā€™s what it looks like to support JSON ļ¬les ā€¦
The Types ļ¬eld is the UTI of the type you want to support (e.g. public.json, public.image).
The CFBundleTypeRole and LSHandlerRank say how you handle this kind of document.
Are you the primary editor and owner of this type or is it just something you can open?
You can add an icon for the ļ¬le type too.
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Declaring your own document type
You might have a custom document type that your application edits
You can add this under Exported UTIs in the same place in Project Settings
Hereā€™s an example of adding an ā€œemojiartā€ type of document ā€¦
ā€¦ and then add it as a
supported Document Type
This is the ā€œUTIā€ that we keep referring to.

Itā€™s like public.json is for JSON.
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Opening documents at the request of other apps (including Files)
A user can now click on a document of your type in Files (or another app can ask to open one)
When this happens, your AppDelegate gets a message sent to it ā€¦
func application(UIApplication, open: URL, options: [UIApplicationOpenURLOptionsKey:Any]) -> Bool
We havenā€™t discussed the AppDelegate yet, but itā€™s just a swift ļ¬le with some methods in it.
Inside here, you can ask your UIDocumentBrowserViewController to show this document ā€¦
let uidbvc = window?.rootViewController as? UIDBVC // since itā€™s ā€œarrowedā€ in storyboard
uidbvc.revealDocument(at: URL, importIfNeeded: true) { (url, error) in
if error != nil {
// present a UIDocument at url modally (more on how to do this in a moment)
} else {
// handle the error
}
}
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Enabling UIDocumentBrowserViewController
To make all this work, you need an entry in your Info.plist.
You can add it the same way we added AppTransportSecurity (right click in Info.plist).
Xcode template
Luckily, an Xcode template exists to do all of the above conļ¬guration for us
CS193p

Fall 2017-18
UIDocumentBrowserViewController
What is in the template?
A stub for Document Types in Project Settings (supports public.image ļ¬le types)
The Info.plist entry Supports Document Browser = YES
The code in AppDelegate to reveal a document
A stubbed out UIDocument subclass (with empty contents and load(fromContents) methods)
A stubbed out MVC to display a document (just calls UIDocumentā€™s open and close methods)
A subclass of UIDocumentBrowserViewController (with almost everything implemented)
What you need to do ā€¦
1. Use your UIDocument subclass instead of the stubbed out one
2. Use your document-viewing MVC code (already using UIDocument) instead of stub
3. Add code to UIDBVC subclass to ā€¦
a. conļ¬gure the UIDBVC (allow multiple selection? creation of new documents? etc.)
b. specify the url of a template document to copy to create new documents
c. present your document-viewing MVC modally given the url of a document
4. Update the Document Types in Project Settings to be your types (instead of public.image)
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Steps 1 and 2
As long as you properly implement UIDocument in your MVC, this is no extra work
Step 3a: Conļ¬guring the UIDBVC
This happens in its viewDidLoad ā€¦
override func viewDidLoad() {
super.viewDidLoad()
delegate = self // the guts of making UIDBVC work are in its delegate methods
allowsDocumentCreation = true
allowsPickingMultipleItems = true
browserUserInterfaceStyle = .dark
view.tintColor = .white
}
Set these as you wish.
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Steps 3b: Specifying the ā€œnew documentā€ template URL
This happens in this UIDBVC delegate method ā€¦
func documentBrowser(_ controller: UIDBVC,
didRequestDocumentCreationWithHandler handler: @escaping (URL?, UIDBVC.ImportMode) -> Void
) {
let url: URL? = ā€¦ // where your blank, template document can be found
importHandler(url, .copy or .move)
}
Usually you would specify .copy, but you could create a new template each time and .move.
Likely you would have some code here that creates that blank template (or ship with your app).
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Aside: Presenting an MVC without segueing
We havenā€™t covered how to present MVCs in any other way except by segueing.
So letā€™s cover it now!
Itā€™s very easy. You present a new MVC from an existing MVC using present(animated:) ā€¦
let newVC: UIViewController = ā€¦
existingVC.present(newVC, animated: true) {
// completion handler called when the presentation completes animating
// (can be left out entirely if you donā€™t need to do anything upon completion)
}
The real trick is ā€œwhere do I get newMVC from?ā€
Answer: you get it from your storyboard using its identiļ¬er which you set in Identity Inspector
let storyboard = UIStoryboard(name: ā€œMainā€, bundle: nil) // Main.storyboard
if let newVC = storyboard.instantiateViewController(withIdentifier: ā€œfooā€) as? MyDocVC {
// ā€œprepareā€ newMVC and then present(animated:) it
}
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Steps 3c: Presenting your document MVC modally
The Xcode template stubs out a function called presentDocument(at: URL) to do this ā€¦
func presentDocument(at url: URL) {
let story = UIStoryboard(name: ā€œMainā€, bundle: nil)
if let docvc = story.instantiateViewController(withIdentifier: ā€œDocVCā€) as? DocVC {
docvc.document = MyDocument(fileURL: url)
present(docvc, animated: true)
}
}
You can call this function anything you want.
But the point is that it takes a URL to one of your documents and you show it.
The Xcode template then calls this from the appropriate delegate methods in UIDBVC.
Thatā€™s all you have to do to get UIDBVC working.
CS193p

Fall 2017-18
UIDocumentBrowserViewController
Step 4: Specifying your types
Unless your app opens public.image ļ¬les, youā€™ll need to change that in Project Settings
For your homework, for example, youā€™ll probably need to invent a new type for Image Gallery
CS193p

Fall 2017-18
Demo Code
Download the demo code from todayā€™s lecture.

More Related Content

What's hot

HexRaysCodeXplorer: make object-oriented RE easier
HexRaysCodeXplorer: make object-oriented RE easierHexRaysCodeXplorer: make object-oriented RE easier
HexRaysCodeXplorer: make object-oriented RE easierAlex Matrosov
Ā 
Getting started with C# Programming
Getting started with C# ProgrammingGetting started with C# Programming
Getting started with C# ProgrammingBhushan Mulmule
Ā 
Basics of JavaScript
Basics of JavaScriptBasics of JavaScript
Basics of JavaScriptBala Narayanan
Ā 
What is String in Java?
What is String in Java?What is String in Java?
What is String in Java?RAKESH P
Ā 
Ajax and JavaScript Bootcamp
Ajax and JavaScript BootcampAjax and JavaScript Bootcamp
Ajax and JavaScript BootcampAndreCharland
Ā 
{"JSON, Swift and Type Safety" : "It's a wrap"}
{"JSON, Swift and Type Safety" : "It's a wrap"}{"JSON, Swift and Type Safety" : "It's a wrap"}
{"JSON, Swift and Type Safety" : "It's a wrap"}Anthony Levings
Ā 
Javascript basic course
Javascript basic courseJavascript basic course
Javascript basic courseTran Khoa
Ā 
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...GeeksLab Odessa
Ā 
Know your Javascript Engine
Know your Javascript EngineKnow your Javascript Engine
Know your Javascript Enginezipeng zhang
Ā 
Few simple-type-tricks in scala
Few simple-type-tricks in scalaFew simple-type-tricks in scala
Few simple-type-tricks in scalaRuslan Shevchenko
Ā 
Using Xcore with Xtext
Using Xcore with XtextUsing Xcore with Xtext
Using Xcore with XtextHolger Schill
Ā 
javascript objects
javascript objectsjavascript objects
javascript objectsVijay Kalyan
Ā 
Xbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for JavaXbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for Javameysholdt
Ā 
New c sharp3_features_(linq)_part_i
New c sharp3_features_(linq)_part_iNew c sharp3_features_(linq)_part_i
New c sharp3_features_(linq)_part_iNico Ludwig
Ā 
JavaScript: Patterns, Part 2
JavaScript: Patterns, Part  2JavaScript: Patterns, Part  2
JavaScript: Patterns, Part 2Chris Farrell
Ā 
Introduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita GanesanIntroduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita GanesanKavita Ganesan
Ā 

What's hot (20)

HexRaysCodeXplorer: make object-oriented RE easier
HexRaysCodeXplorer: make object-oriented RE easierHexRaysCodeXplorer: make object-oriented RE easier
HexRaysCodeXplorer: make object-oriented RE easier
Ā 
Getting started with C# Programming
Getting started with C# ProgrammingGetting started with C# Programming
Getting started with C# Programming
Ā 
Basics of JavaScript
Basics of JavaScriptBasics of JavaScript
Basics of JavaScript
Ā 
What is String in Java?
What is String in Java?What is String in Java?
What is String in Java?
Ā 
Reversing JavaScript
Reversing JavaScriptReversing JavaScript
Reversing JavaScript
Ā 
Ajax and JavaScript Bootcamp
Ajax and JavaScript BootcampAjax and JavaScript Bootcamp
Ajax and JavaScript Bootcamp
Ā 
{"JSON, Swift and Type Safety" : "It's a wrap"}
{"JSON, Swift and Type Safety" : "It's a wrap"}{"JSON, Swift and Type Safety" : "It's a wrap"}
{"JSON, Swift and Type Safety" : "It's a wrap"}
Ā 
Javascript basic course
Javascript basic courseJavascript basic course
Javascript basic course
Ā 
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...
Java/Scala Lab 2016. Š“Ń€ŠøŠ³Š¾Ń€ŠøŠ¹ ŠšŃ€Š°Š²Ń†Š¾Š²: Š ŠµŠ°Š»ŠøŠ·Š°Ń†Šøя Šø тŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ DAO сŠ»Š¾Ń с Š½...
Ā 
Know your Javascript Engine
Know your Javascript EngineKnow your Javascript Engine
Know your Javascript Engine
Ā 
Few simple-type-tricks in scala
Few simple-type-tricks in scalaFew simple-type-tricks in scala
Few simple-type-tricks in scala
Ā 
Day 2
Day 2Day 2
Day 2
Ā 
oojs
oojsoojs
oojs
Ā 
Using Xcore with Xtext
Using Xcore with XtextUsing Xcore with Xtext
Using Xcore with Xtext
Ā 
Autoboxing And Unboxing In Java
Autoboxing And Unboxing In JavaAutoboxing And Unboxing In Java
Autoboxing And Unboxing In Java
Ā 
javascript objects
javascript objectsjavascript objects
javascript objects
Ā 
Xbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for JavaXbase - Implementing Domain-Specific Languages for Java
Xbase - Implementing Domain-Specific Languages for Java
Ā 
New c sharp3_features_(linq)_part_i
New c sharp3_features_(linq)_part_iNew c sharp3_features_(linq)_part_i
New c sharp3_features_(linq)_part_i
Ā 
JavaScript: Patterns, Part 2
JavaScript: Patterns, Part  2JavaScript: Patterns, Part  2
JavaScript: Patterns, Part 2
Ā 
Introduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita GanesanIntroduction to Java Strings, By Kavita Ganesan
Introduction to Java Strings, By Kavita Ganesan
Ā 

Similar to Persistence And Documents

Custom view
Custom viewCustom view
Custom viewSV.CO
Ā 
Ts archiving
Ts   archivingTs   archiving
Ts archivingConfiz
Ā 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practicesIwan van der Kleijn
Ā 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development IntroLuis Azevedo
Ā 
Javascript Templating
Javascript TemplatingJavascript Templating
Javascript Templatingbcruhl
Ā 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core DataInferis
Ā 
An Introduction to TypeScript
An Introduction to TypeScriptAn Introduction to TypeScript
An Introduction to TypeScriptWrapPixel
Ā 
Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0Frost
Ā 
The advantage of developing with TypeScript
The advantage of developing with TypeScript The advantage of developing with TypeScript
The advantage of developing with TypeScript Corley S.r.l.
Ā 
Classes1
Classes1Classes1
Classes1phanleson
Ā 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best PraticesChengHui Weng
Ā 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987乐ē¾¤ 陈
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)Ary Borenszweig
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)Ary Borenszweig
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)Crystal Language
Ā 
Getting started with typescript and angular 2
Getting started with typescript  and angular 2Getting started with typescript  and angular 2
Getting started with typescript and angular 2Knoldus Inc.
Ā 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design PatternsStefano Fago
Ā 

Similar to Persistence And Documents (20)

Custom view
Custom viewCustom view
Custom view
Ā 
Ts archiving
Ts   archivingTs   archiving
Ts archiving
Ā 
Type script - advanced usage and practices
Type script  - advanced usage and practicesType script  - advanced usage and practices
Type script - advanced usage and practices
Ā 
iPhone Development Intro
iPhone Development IntroiPhone Development Intro
iPhone Development Intro
Ā 
Javascript Templating
Javascript TemplatingJavascript Templating
Javascript Templating
Ā 
Adventures in Multithreaded Core Data
Adventures in Multithreaded Core DataAdventures in Multithreaded Core Data
Adventures in Multithreaded Core Data
Ā 
An Introduction to TypeScript
An Introduction to TypeScriptAn Introduction to TypeScript
An Introduction to TypeScript
Ā 
Serialization
SerializationSerialization
Serialization
Ā 
Day 1
Day 1Day 1
Day 1
Ā 
Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0Building an api using golang and postgre sql v1.0
Building an api using golang and postgre sql v1.0
Ā 
The advantage of developing with TypeScript
The advantage of developing with TypeScript The advantage of developing with TypeScript
The advantage of developing with TypeScript
Ā 
AngularConf2015
AngularConf2015AngularConf2015
AngularConf2015
Ā 
Classes1
Classes1Classes1
Classes1
Ā 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best Pratices
Ā 
Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987Compiler2016 by abcdabcd987
Compiler2016 by abcdabcd987
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)
Ā 
Crystal internals (part 1)
Crystal internals (part 1)Crystal internals (part 1)
Crystal internals (part 1)
Ā 
Getting started with typescript and angular 2
Getting started with typescript  and angular 2Getting started with typescript  and angular 2
Getting started with typescript and angular 2
Ā 
Uncommon Design Patterns
Uncommon Design PatternsUncommon Design Patterns
Uncommon Design Patterns
Ā 

More from SV.CO

Handout level-1-module-1
Handout   level-1-module-1Handout   level-1-module-1
Handout level-1-module-1SV.CO
Ā 
Building complex input screens
Building complex input screensBuilding complex input screens
Building complex input screensSV.CO
Ā 
Working with the Web: ā€ØDecoding JSON
Working with the Web: ā€ØDecoding JSONWorking with the Web: ā€ØDecoding JSON
Working with the Web: ā€ØDecoding JSONSV.CO
Ā 
Saving Data
Saving DataSaving Data
Saving DataSV.CO
Ā 
Alerts notification
Alerts notificationAlerts notification
Alerts notificationSV.CO
Ā 
UI Dynamics
UI DynamicsUI Dynamics
UI DynamicsSV.CO
Ā 
Practical animation
Practical animationPractical animation
Practical animationSV.CO
Ā 
Segues and navigation controllers
Segues and navigation controllersSegues and navigation controllers
Segues and navigation controllersSV.CO
Ā 
Camera And Email
Camera And EmailCamera And Email
Camera And EmailSV.CO
Ā 
Scroll views
Scroll viewsScroll views
Scroll viewsSV.CO
Ā 
Intermediate table views
Intermediate table viewsIntermediate table views
Intermediate table viewsSV.CO
Ā 
Table views
Table viewsTable views
Table viewsSV.CO
Ā 
Closures
ClosuresClosures
ClosuresSV.CO
Ā 
Protocols
ProtocolsProtocols
ProtocolsSV.CO
Ā 
App anatomy and life cycle
App anatomy and life cycleApp anatomy and life cycle
App anatomy and life cycleSV.CO
Ā 
Extensions
ExtensionsExtensions
ExtensionsSV.CO
Ā 
Gestures
GesturesGestures
GesturesSV.CO
Ā 
View controller life cycle
View controller life cycleView controller life cycle
View controller life cycleSV.CO
Ā 
Controls in action
Controls in actionControls in action
Controls in actionSV.CO
Ā 
Auto layout and stack views
Auto layout and stack viewsAuto layout and stack views
Auto layout and stack viewsSV.CO
Ā 

More from SV.CO (20)

Handout level-1-module-1
Handout   level-1-module-1Handout   level-1-module-1
Handout level-1-module-1
Ā 
Building complex input screens
Building complex input screensBuilding complex input screens
Building complex input screens
Ā 
Working with the Web: ā€ØDecoding JSON
Working with the Web: ā€ØDecoding JSONWorking with the Web: ā€ØDecoding JSON
Working with the Web: ā€ØDecoding JSON
Ā 
Saving Data
Saving DataSaving Data
Saving Data
Ā 
Alerts notification
Alerts notificationAlerts notification
Alerts notification
Ā 
UI Dynamics
UI DynamicsUI Dynamics
UI Dynamics
Ā 
Practical animation
Practical animationPractical animation
Practical animation
Ā 
Segues and navigation controllers
Segues and navigation controllersSegues and navigation controllers
Segues and navigation controllers
Ā 
Camera And Email
Camera And EmailCamera And Email
Camera And Email
Ā 
Scroll views
Scroll viewsScroll views
Scroll views
Ā 
Intermediate table views
Intermediate table viewsIntermediate table views
Intermediate table views
Ā 
Table views
Table viewsTable views
Table views
Ā 
Closures
ClosuresClosures
Closures
Ā 
Protocols
ProtocolsProtocols
Protocols
Ā 
App anatomy and life cycle
App anatomy and life cycleApp anatomy and life cycle
App anatomy and life cycle
Ā 
Extensions
ExtensionsExtensions
Extensions
Ā 
Gestures
GesturesGestures
Gestures
Ā 
View controller life cycle
View controller life cycleView controller life cycle
View controller life cycle
Ā 
Controls in action
Controls in actionControls in action
Controls in action
Ā 
Auto layout and stack views
Auto layout and stack viewsAuto layout and stack views
Auto layout and stack views
Ā 

Recently uploaded

Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)
Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)
Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)lakshayb543
Ā 
Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...SeƔn Kennedy
Ā 
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfGrade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfJemuel Francisco
Ā 
Transaction Management in Database Management System
Transaction Management in Database Management SystemTransaction Management in Database Management System
Transaction Management in Database Management SystemChristalin Nelson
Ā 
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfAMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfphamnguyenenglishnb
Ā 
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfInclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfTechSoup
Ā 
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfLike-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfMr Bounab Samir
Ā 
Global Lehigh Strategic Initiatives (without descriptions)
Global Lehigh Strategic Initiatives (without descriptions)Global Lehigh Strategic Initiatives (without descriptions)
Global Lehigh Strategic Initiatives (without descriptions)cama23
Ā 
FILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinoFILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinojohnmickonozaleda
Ā 
Keynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designKeynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designMIPLM
Ā 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomnelietumpap1
Ā 
Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Celine George
Ā 
Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Jisc
Ā 
What is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPWhat is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPCeline George
Ā 
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptx
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptxECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptx
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptxiammrhaywood
Ā 
Choosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for ParentsChoosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for Parentsnavabharathschool99
Ā 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxAnupkumar Sharma
Ā 
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxBarangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxCarlos105
Ā 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Mark Reed
Ā 

Recently uploaded (20)

Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)
Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)
Visit to a blind student's schoolšŸ§‘ā€šŸ¦ÆšŸ§‘ā€šŸ¦Æ(community medicine)
Ā 
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptxLEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
LEFT_ON_C'N_ PRELIMS_EL_DORADO_2024.pptx
Ā 
Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...Student Profile Sample - We help schools to connect the data they have, with ...
Student Profile Sample - We help schools to connect the data they have, with ...
Ā 
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdfGrade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Grade 9 Quarter 4 Dll Grade 9 Quarter 4 DLL.pdf
Ā 
Transaction Management in Database Management System
Transaction Management in Database Management SystemTransaction Management in Database Management System
Transaction Management in Database Management System
Ā 
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdfAMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
AMERICAN LANGUAGE HUB_Level2_Student'sBook_Answerkey.pdf
Ā 
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdfInclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Inclusivity Essentials_ Creating Accessible Websites for Nonprofits .pdf
Ā 
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdfLike-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Like-prefer-love -hate+verb+ing & silent letters & citizenship text.pdf
Ā 
Global Lehigh Strategic Initiatives (without descriptions)
Global Lehigh Strategic Initiatives (without descriptions)Global Lehigh Strategic Initiatives (without descriptions)
Global Lehigh Strategic Initiatives (without descriptions)
Ā 
FILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipinoFILIPINO PSYCHology sikolohiyang pilipino
FILIPINO PSYCHology sikolohiyang pilipino
Ā 
Keynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-designKeynote by Prof. Wurzer at Nordex about IP-design
Keynote by Prof. Wurzer at Nordex about IP-design
Ā 
ENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choomENGLISH6-Q4-W3.pptxqurter our high choom
ENGLISH6-Q4-W3.pptxqurter our high choom
Ā 
Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17Difference Between Search & Browse Methods in Odoo 17
Difference Between Search & Browse Methods in Odoo 17
Ā 
Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...Procuring digital preservation CAN be quick and painless with our new dynamic...
Procuring digital preservation CAN be quick and painless with our new dynamic...
Ā 
What is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERPWhat is Model Inheritance in Odoo 17 ERP
What is Model Inheritance in Odoo 17 ERP
Ā 
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptx
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptxECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptx
ECONOMIC CONTEXT - PAPER 1 Q3: NEWSPAPERS.pptx
Ā 
Choosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for ParentsChoosing the Right CBSE School A Comprehensive Guide for Parents
Choosing the Right CBSE School A Comprehensive Guide for Parents
Ā 
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptxMULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
MULTIDISCIPLINRY NATURE OF THE ENVIRONMENTAL STUDIES.pptx
Ā 
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptxBarangay Council for the Protection of Children (BCPC) Orientation.pptx
Barangay Council for the Protection of Children (BCPC) Orientation.pptx
Ā 
Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)Influencing policy (training slides from Fast Track Impact)
Influencing policy (training slides from Fast Track Impact)
Ā 

Persistence And Documents

  • 1. CS193p Fall 2017-18 Stanford CS193p Developing Applications for iOS Fall 2017-18
  • 2. CS193p Fall 2017-18 Today Emoji Art Demo continued ā€¦ UITextField to add more Emoji Persistence UserDefaults Property List Archiving and Codable Filesystem Core Data Cloud Kit UIDocument UIDocumentBrowserViewController
  • 3. CS193p Fall 2017-18 UserDefaults A very lightweight and limited database UserDefaults is essentially a very tiny database that persists between launchings of your app. Great for things like ā€œsettingsā€ and such. Do not use it for anything big! What can you store there? You are limited in what you can store in UserDefaults: it only stores Property List data. A Property List is any combo of Array, Dictionary, String, Date, Data or a number (Int, etc.). This is an old Objective-C API with no type that represents all those, so this API uses Any. If this were a new, Swift-style API, it would almost certainly not use Any. (Likely there would be a protocol or some such that those types would implement.) What does the API look like? Itā€™s ā€œcoreā€ functionality is simple. It just stores and retrieves Property Lists by key ā€¦ func set(Any?, forKey: String) // the Any has to be a Property List (or crash) func object(forKey: String) -> Any? // the Any is guaranteed to be a Property List
  • 4. CS193p Fall 2017-18 UserDefaults Reading and Writing You donā€™t usually create one of these databases with UserDefaults(). Instead, you use the static (type) var called standard ā€¦ let defaults = UserDefaults.standard Setting a value in the database is easy since the set method takes an Any?. defaults.set(3.1415, forKey: ā€œpiā€) // 3.1415 is a Double which is a Property List type defaults.set([1,2,3,4,5], forKey: ā€œMy Arrayā€) // Array and Int are both Property Lists defaults.set(nil, forKey: ā€œSome Settingā€) // removes any data at that key You can pass anything as the ļ¬rst argument as long as itā€™s a combo of Property List types. UserDefaults also has convenience API for getting many of the Property List types. func double(forKey: String) -> Double func array(forKey: String) -> [Any]? // returns nil if non-Array at that key func dictionary(forKey: String) -> [String:Any]? // note that keys in return are Strings The Any in the returned values will, of course, be a Property List type.
  • 5. CS193p Fall 2017-18 UserDefaults Saving the database Your changes will be occasionally autosaved. But you can force them to be saved at any time with synchronize ā€¦ if !defaults.synchronize() { // failed! but not clear what you can do about it } (itā€™s not ā€œfreeā€ to synchronize, but itā€™s not that expensive either)
  • 6. CS193p Fall 2017-18 Archiving There are two mechanisms for making ANY object persistent A historical method which is how, for example, the storyboard is made persistent. A new mechanism in iOS 11 which is supported directly by the Swift language environment. Weā€™re only going to talk in detail about the second of these. Since itā€™s supported by the language, itā€™s much more likely to be the one youā€™d use.
  • 7. CS193p Fall 2017-18 Archiving NSCoder (old) mechanism Requires all objects in an object graph to implement these two methods ā€¦ func encode(with aCoder: NSCoder) init(coder: NSCoder) Essentially you store all of your objectā€™s data in the coderā€™s dictionary. Then you have to be able to initialize your object from a coderā€™s dictionary. References within the object graph are handled automatically. You can then take an object graph and turn it into a Data (via NSKeyedArchiver). And then turn a Data back into an object graph (via NSKeyedUnarchiver). Once you have a Data, you can easily write it to a ļ¬le or otherwise pass it around.
  • 8. CS193p Fall 2017-18 Archiving Codable (new) mechanism Also is essentially a way to store all the vars of an object into a dictionary. To do this, all the objects in the graph of objects you want to store must implement Codable. But the difference is that, for standard Swift types, Swift will do this for you. If you have non-standard types, you can do something similar to the old method. Some of the standard types (that youā€™d recognize) that are automatically Codable by Swift ā€¦ String, Bool, Int, Double, Float Optional Array, Dictionary, Set, Data URL Date, DateComponents, DateInterval, Calendar CGFloat, AffineTransform, CGPoint, CGSize, CGRect, CGVector IndexPath, IndexSet NSRange
  • 9. CS193p Fall 2017-18 Archiving Codable (new) mechanism Once your object graph is all Codable, you can convert it to either JSON or a Property List. let object: MyType = ā€¦ let jsonData: Data? = try? JSONEncoder().encode(object) Note that this encode throws. You can catch and ļ¬nd errors easily (next slide). By the way, you can make a String object out of this Data like this ā€¦ let jsonString = String(data: jsonData!, encoding: .utf8) // JSON is always utf8 To get your object graph back from the JSON ā€¦ if let myObject: MyType = try? JSONDecoder().decode(MyType.self, from: jsonData!) { } JSON is not ā€œstrongly typed.ā€ So things like Date or URL are just strings. Swift handles all this automatically and is even conļ¬gurable, for example ā€¦ let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 // or .secondsSince1970, etc.
  • 10. CS193p Fall 2017-18 Archiving Codable (new) mechanism Hereā€™s what it might look like to catch errors during a decoding. The thing decode throws is an enum of type DecodingError. Note how we can get the associated values of the enum similar to how we do with switch. do { let object = try JSONDecoder().decode(MyType.self, from: jsonData!) // success, do something with object } catch DecodingError.keyNotFound(let key, let context) { print(ā€œcouldnā€™t find key (key) in JSON: (context.debugDescription)ā€) } catch DecodingError.valueNotFound(let type, let context) { } catch DecodingError.typeMismatch(let type, let context) { } catch DecodingError.dataCorrupted(let context) { }
  • 11. CS193p Fall 2017-18 Archiving Codable Example So how do you make your data types Codable? Usually you just say so ā€¦ struct MyType : Codable { var someDate: Date var someString: String var other: SomeOtherType // SomeOtherType has to be Codable too! } If your vars are all also Codable (standard types all are), then youā€™re done! The JSON for this might look like .. { ā€œsomeDateā€ : ā€œ2017-11-05T16:30:00Zā€, ā€œsomeStringā€ : ā€œHelloā€, ā€œotherā€ : <whatever SomeOtherType looks like in JSON> }
  • 12. CS193p Fall 2017-18 Archiving Codable Example Sometimes JSON keys might have different names than your var names (or not be included). For example, someDate might be some_date. You can conļ¬gure this by adding a private enum to your type called CodingKeys like this ā€¦ struct MyType : Codable { var someDate: Date var someString: String var other: SomeOtherType // SomeOtherType has to be Codable too! private enum CodingKeys : String, CodingKey { case someDate = ā€œsome_dateā€ // note that the someString var will now not be included in the JSON case other // this key is also called ā€œotherā€ in JSON } }
  • 13. CS193p Fall 2017-18 Archiving Codable Example You can participate directly in the decoding by implementing the decoding initializer ā€¦ struct MyType : Codable { var someDate: Date var someString: String var other: SomeOtherType // SomeOtherType has to be Codable too! init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) someDate = try container.decode(Date.self, forKey: .someDate) // process rest of vars, perhaps validating input, etc. ā€¦ } } Note that this init throws, so we donā€™t need do { } inside it (it will just rethrow). Also note the ā€œkeysā€ are from the CodingKeys enum on the previous slide (e.g. .someDate).
  • 14. CS193p Fall 2017-18 Archiving Codable Example You can participate directly in the decoding by implementing the decoding initializer ā€¦ class MyType : Codable { var someDate: Date var someString: String var other: SomeOtherType // SomeOtherType has to be Codable too! init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) someDate = try container.decode(Date.self, forKey: .someDate) // process rest of vars, perhaps validating input, etc. ā€¦ let superDecoder = try container.superDecoder() try super.init(from: superDecoder) // only if class } } Donā€™t call super.init with your own decoder (use your containerā€™s superDecoder()).
  • 15. CS193p Fall 2017-18 Archiving Codable Example You can participate directly in the decoding by implementing the decoding initializer ā€¦ struct MyType : Codable { var someDate: Date var someString: String var other: SomeOtherType // SomeOtherType has to be Codable too! func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // there are other containers too (e.g. an unkeyed (i.e. array) container) ā€¦ try container.encode(someDate, forKey: .someDate) // encode the rest of vars, perhaps transforming them, etc. ā€¦ } }
  • 16. CS193p Fall 2017-18 File System Your application sees iOS ļ¬le system like a normal Unix ļ¬lesystem It starts at /. There are ļ¬le protections, of course, like normal Unix, so you canā€™t see everything. In fact, you can only read and write in your applicationā€™s ā€œsandboxā€. Why sandbox? Security (so no one else can damage your application) Privacy (so no other applications can view your applicationā€™s data) Cleanup (when you delete an application, everything it has ever written goes with it) So whatā€™s in this ā€œsandboxā€? Application directory ā€” Your executable, .storyboards, .jpgs, etc.; not writeable. Documents directory ā€” Permanent storage created by and always visible to the user. Application Support directory ā€” Permanent storage not seen directly by the user. Caches directory ā€” Store temporary ļ¬les here (this is not backed up by iTunes). Other directories (see documentation) ā€¦
  • 17. CS193p Fall 2017-18 File System Getting a path to these special sandbox directories FileManager (along with URL) is what you use to ļ¬nd out about whatā€™s in the ļ¬le system. You can, for example, ļ¬nd the URL to these special system directories like this ... let url: URL = FileManager.default.url( for directory: FileManager.SearchPathDirectory.documentDirectory, // for example in domainMask: .userDomainMask // always .userDomainMask on iOS appropriateFor: nil, // only meaningful for ā€œreplaceā€ ļ¬le operations create: true // whether to create the system directory if it doesnā€™t already exist ) Examples of SearchPathDirectory values .documentDirectory, .applicationSupportDirectory, .cachesDirectory, etc.
  • 18. CS193p Fall 2017-18 URL Building on top of these system paths URL methods: func appendingPathComponent(String) -> URL func appendingPathExtension(String) -> URL // e.g. ā€œjpgā€ Finding out about whatā€™s at the other end of a URL var isFileURL: Bool // is this a ļ¬le URL (whether ļ¬le exists or not) or something else? func resourceValues(for keys: [URLResourceKey]) throws -> [URLResourceKey:Any]? Example keys: .creationDateKey, .isDirectoryKey, .fileSizeKey
  • 19. CS193p Fall 2017-18 File System Data Reading binary data from a URL ā€¦ init(contentsOf: URL, options: Data.ReadingOptions) throws Writing binary data to a URL ā€¦ func write(to url: URL, options: Data.WritingOptions) throws -> Bool The options can be things like .atomic (write to tmp ļ¬le, then swap) or .withoutOverwriting. Notice that this function throws.
  • 20. CS193p Fall 2017-18 File System FileManager Provides utility operations. e.g., fileExists(atPath: String) -> Bool Can create and enumerate directories; move, copy, delete ļ¬les; etc. Thread safe (as long as a given instance is only ever used in one thread). Also has a delegate with lots of ā€œshouldā€ methods (to do an operation or proceed after an error). And plenty more. Check out the documentation.
  • 21. CS193p Fall 2017-18 Core Data Database Sometimes you need to store large amounts of data locally in a database. And you need to search through it in an efļ¬cient, sophisticated manner. Enter Core Data Object-oriented database. Very, very powerful framework in iOS (unfortunately no time to cover it this quarter). Check out Winter of 2016-17ā€™s iTunesU for a full pair of lectures on it! Itā€™s a way of creating an object graph backed by a database Usually backed by SQL (but also can do XML or just in memory). How does it work? Create a visual mapping (using Xcode tool) between database and objects. Create and query for objects using object-oriented API. Access the ā€œcolumns in the database tableā€ using vars on those objects.
  • 22. CS193p Fall 2017-18 Hereā€™s what the graphical database schema editor looks like.
  • 23. CS193p Fall 2017-18 Core Data So how do you access all of this stuff in your code? Core Data is access via an NSManagedObjectContext. It is the hub around which all Core Data activity turns. The code that the Use Core Data button adds creates one for you in your AppDelegate.
  • 24. CS193p Fall 2017-18 Core Data What does it look like to create/update objects in the database? It looks a lot like accessing normal Swift objects ā€¦ let context: NSManagedObjectContext = ... if let tweet = Tweet(context: context) { tweet.text = ā€œ140 characters of pure joyā€ tweet.created = Date() let joe = TwitterUser(context: tweet.managedObjectContext) tweet.tweeter = joe tweet.tweeter.name = ā€œJoe Schmoā€ }
  • 25. CS193p Fall 2017-18 Core Data Deleting objects context.delete(tweet) Saving changes You must explicitly save any changes to a context, but note that this throws. do { try context.save() } catch { // deal with error } However, we usually use a UIManagedDocument which autosaves for us. More on UIDocument-based code in a few slides ā€¦
  • 26. CS193p Fall 2017-18 Querying Searching for objects in the database Letā€™s say we want to query for all TwitterUsers ... let request: NSFetchRequest<TwitterUser> = TwitterUser.fetchRequest() ... who have created a tweet in the last 24 hours ... let yesterday = Date(timeIntervalSinceNow:-24*60*60) as NSDate request.predicate = NSPredicate(format: ā€œany tweets.created > %@ā€, yesterday) ... sorted by the TwitterUserā€™s name ... request.sortDescriptors = [NSSortDescriptor(key: ā€œnameā€, ascending: true)] let context: NSManagedObjectContext = ... let recentTweeters = try? context.fetch(request) Returns an empty Array (not nil) if it succeeds and there are no matches in the database. Returns an Array of NSManagedObjects (or subclasses thereof) if there were any matches. And obviously the try fails if the fetch fails.
  • 27. CS193p Fall 2017-18 Core Data And so much more! Very efļ¬cient Support for multithreading Close integration with UITableView (for obvious reasons) Optimistic locking (deleteConflictsForObject) Rolling back unsaved changes Undo/Redo Staleness (how long after a fetch until a refetch of an object is required?) Etc., etc. ā€¦
  • 28. CS193p Fall 2017-18 Cloud Kit Cloud Kit A database in the cloud. Simple to use, but with very basic ā€œdatabaseā€ operations. Since itā€™s on the network, accessing the database could be slow or even impossible. This requires some thoughtful programming. No time for this one either this quarter, but check Spring of 2015-16ā€™s iTunesU for full demo. Important Components Record Type - like a class or struct Fields - like vars in a class or struct Record - an ā€œinstanceā€ of a Record Type Reference - a ā€œpointerā€ to another Record Database - a place where Records are stored Zone - a sub-area of a Database Container - collection of Databases Query - an Database search Subscription - a ā€œstanding Queryā€ which sends push notiļ¬cations when changes occur
  • 29. CS193p Fall 2017-18 Cloud Kit You must enable iCloud in your Project Settings Under Capabilities tab, turn on iCloud (On/Off switch).
  • 30. CS193p Fall 2017-18 Cloud Kit You must enable iCloud in your Project Settings Under Capabilities tab, turn on iCloud (On/Off switch). Then, choose CloudKit from the Services.
  • 31. CS193p Fall 2017-18 Cloud Kit You must enable iCloud in your Project Settings Under Capabilities tab, turn on iCloud (On/Off switch). Then, choose CloudKit from the Services. Youā€™ll also see a CloudKit Dashboard button which will take you to the Cloud Kit Dashboard.
  • 32. CS193p Fall 2017-18 Cloud Kit Cloud Kit Dashboard A web-based UI to look at everything you are storing. Shows you all your Record Types and Fields as well as the data in Records. You can add new Record Types and Fields and also turn on/off indexes for various Fields.
  • 33. CS193p Fall 2017-18 Cloud Kit Dynamic Schema Creation But you donā€™t have to create your schema in the Dashboard. You can create it ā€œorganicallyā€ by simply creating and storing things in the database. When you store a record with a new, never-before-seen Record Type, it will create that type. Or if you add a Field to a Record, it will automatically create a Field for it in the database. This only works during Development, not once you deploy to your users.
  • 34. CS193p Fall 2017-18 Cloud Kit What it looks like to create a record in a database let db = CKContainer.default.publicCloudDatabase let tweet = CKRecord(ā€œTweetā€) tweet[ā€œtextā€] = ā€œ140 characters of pure joyā€ let tweeter = CKRecord(ā€œTwitterUserā€) tweet[ā€œtweeterā€] = CKReference(record: tweeter, action: .deleteSelf) db.save(tweet) { (savedRecord: CKRecord?, error: NSError?) -> Void in if error == nil { // hooray! } else if error?.errorCode == CKErrorCode.NotAuthenticated.rawValue { // tell user he or she has to be logged in to iCloud for this to work! } else { // report other errors (there are 29 different CKErrorCodes!) } }
  • 35. CS193p Fall 2017-18 Cloud Kit What it looks like to query for records in a database let db = CKContainer.default.publicCloudDatabase let predicate = NSPredicate(format: ā€œtext contains %@ā€œ, searchString) let query = CKQuery(recordType: ā€œTweetā€, predicate: predicate) db.perform(query) { (records: [CKRecord]?, error: NSError?) in if error == nil { // records will be an array of matching CKRecords } else if error?.errorCode == CKErrorCode.NotAuthenticated.rawValue { // tell user he or she has to be logged in to iCloud for this to work! } else { // report other errors (there are 29 different CKErrorCodes!) } }
  • 36. CS193p Fall 2017-18 Cloud Kit Standing Queries (aka Subscriptions) One of the coolest features of Cloud Kit is its ability to send push notiļ¬cations on changes. All you do is register an NSPredicate and whenever the database changes to match it, boom! Unfortunately, we donā€™t have time to discuss push notiļ¬cations this quarter. If youā€™re interested, check out the UserNotifications framework.
  • 37. CS193p Fall 2017-18 UIDocument When to use UIDocument If your application stores user information in a way the user perceives as a ā€œdocumentā€. If you just want iOS to manage the primary storage of user information. What does UIDocument do? Manages all interaction with storage devices (not just ļ¬lesystem, but also iCloud, Box, etc.). Provides asynchronous opening, writing, reading and closing of ļ¬les. Autosaves your document data. Makes integration with iOS 11ā€™s new Files application essentially free. What do you need to do to make UIDocument work? Subclass UIDocument to add vars to hold the Model of your MVC that shows your ā€œdocumentā€. Then implement one method that writes the Model to a Data and one that reads it from a Data. Thatā€™s it. Now you can use UIDocumentā€™s opening, saving and closing methods as needed. You can also use its ā€œdocument has changedā€ method (or implement undo) to get autosaving.
  • 38. CS193p Fall 2017-18 UIDocument Subclassing UIDocument For simple documents, thereā€™s nothing to do here except add your Model as a var ā€¦ class EmojiArtDocument: UIDocument { var emojiArt: EmojiArt? } There are, of course, methods you can override, but usually you donā€™t need to. Creating a UIDocument Figure out where you want your document to be stored in the ļ¬lesystem ā€¦ var url = FileManager.urls(for: .documentDirectory, in: .userDomainMask).first! url = url.appendingPathComponent(ā€œUntitled.fooā€) Instantiate your subclass by passing that url to UIDocumentā€™s only initializer ā€¦ let myDocument = EmojiArtDocument(fileURL: url) ā€¦ then (eventually) set your Model var(s) on your newly created UIDocument subclass ā€¦ myDocument.emojiArt = ā€¦
  • 39. CS193p Fall 2017-18 UIDocument Creating a Data for your Model Override this method in your UIDocument subclass to convert your Model into a Data. override func contents(forType typeName: String) throws -> Any { return emojiArt converted into a Data } Note that the return type is Any ā€¦ thatā€™s because your ļ¬le format can also be a FileWrapper. A FileWrapper represents a directory full of ļ¬les that make up your document. If for some reason you canā€™t create a Data or FileWrapper, you can throw an error here. Weā€™ll see where that thrown error ends up in a couple of slides. The forType is a UTI (type identiļ¬er) calculated from your fileURLā€™s ļ¬le extension (e.g. .jpg) Weā€™ll see in a few slides how to declare what sorts of ļ¬les (the UTIs) your app deals with.
  • 40. CS193p Fall 2017-18 UIDocument Turning a Data into a Model Override this method in your UIDocument subclass to a Data into an instance of your Model. override func load(fromContents contents: Any, ofType typeName: String?) throws { emojiArt = contents converted into an EmojiArt } Again, you can throw here if you canā€™t create a document from the passed contents.
  • 41. CS193p Fall 2017-18 UIDocument Ready to go! Now you can open your document (i.e. get your Model) ā€¦ myDocument.open { success in if success { // your Model var(s) (e.g. emojiArt) is/are ready to use } else { // there was a problem, check documentState } } This method is asynchronous! The closure is called on the same thread you call open from (the main thread usually). Weā€™ll see more about documentState in a couple of slides.
  • 42. CS193p Fall 2017-18 UIDocument Saving your document You can let your document know that the Model has changed with this method ā€¦ myDocument.updateChangeCount(.done) ā€¦ or you can use UIDocumentā€™s undoManager (no time to cover that, unfortunately!) UIDocument will save your changes automatically at the next best opportunity. Or you can force a save using this method ā€¦ let url = myDocument.fileURL // or something else if you want ā€œsave asā€ myDocument.save(to url: URL, for: UIDocumentSaveOperation) { success in if success { // your Model has successfully been saved } else { // there was a problem, check documentState } } UIDocumentSaveOperation is either .forCreating or .forOverwriting.
  • 43. CS193p Fall 2017-18 UIDocument Closing your document When you are ļ¬nished using a document for now, close it ā€¦ myDocument.close { success in if success { // your Model has successfully been saved and closed // use the open method again if you want to use it } else { // there was a problem, check documentState } }
  • 44. CS193p Fall 2017-18 UIDocument Document State As all this goes on, your document transitions to various states. You can ļ¬nd out what state it is in using this var ā€¦ var documentState: UIDocumentState Possible values ā€¦ .normal ā€” document is open and ready for use! .closed ā€” document is closed and must be opened to be used .savingError ā€” document couldnā€™t be saved (override handleError if you want to know why) .editingDisabled ā€” the document cannot currently be edited (so donā€™t let your UI do that) .progressAvailable ā€” how far a large document is in getting loaded (check progress var) .inConflict ā€” someone edited this document somewhere else (iCloud) To resolve conļ¬‚icts, you access the conļ¬‚icting versions with ā€¦ NSFileVersion.unresolvedConflictVersionsOfItem(at url: URL) -> [NSFileVersion]? For the best UI, you could give your user the choice of which version to use. Or, if your documentā€™s contents are ā€œmergeableā€, you could even do that. documentState can be ā€œobservedā€ using the UIDocumentStateChanged notiļ¬cation (more later).
  • 45. CS193p Fall 2017-18 UIDocument Thumbnail You can specify a thumbnail image for your UIDocument. It can make it much easier for users to ļ¬nd the document they want in Files, for example. Essentially you are going to override the UIDocument method which sets ļ¬le attributes. The attributes are returned as a dictionary. One of the keys is for the thumbnail (itā€™s a convoluted key) ā€¦ override func fileAttributesToWrite(to url: URL, for operation: UIDocumentSaveOperation) throws -> [AnyHashable : Any] { var attributes = try super.fileAttributesToWrite(to: url, for: saveOperation) if let thumbnail: UIImage = ā€¦ { attributes[URLResourceKey.thumbnailDictionaryKey] = [URLThumbnailDictionaryItem.NSThumbnail1024x1024SizeKey:thumbnail] } return attributes } It does not have to be 1024x1024 (it seems to have a minimum size, not sure what).
  • 46. CS193p Fall 2017-18 UIDocument Other var localizedName: String var hasUnsavedChanges: Bool var fileModificationDate: Date? var userActivity: NSUserActivity? // iCloud documents only
  • 47. CS193p Fall 2017-18 UIDocumentBrowserViewController Managing user documents You probably want users to be able to easily manage their documents in a document-based app. Choosing ļ¬les to open, renaming ļ¬les, moving them, accessing iCloud drive, etc. The UIDocumentBrowserViewController (UIDBVC) does all of this for you. Using UIDocument to store your document makes leveraging this UIDBVC easy.
  • 48. CS193p Fall 2017-18 UIDocumentBrowserViewController Managing user documents You probably want users to be able to easily manage their documents in a document-based app. Choosing ļ¬les to open, renaming ļ¬les, moving them, accessing iCloud drive, etc. The UIDocumentBrowserViewController (UIDBVC) does all of this for you. Using UIDocument to store your document makes leveraging this UIDBVC easy. Using the UIDocumentBrowserViewController It has to be the root view controller in your storyboard (i.e. the arrow points to it). Your document-editing MVC will then be presented modally on top of (i.e. takes over the screen).
  • 49. CS193p Fall 2017-18 UIDocumentBrowserViewController What document types can you open? To use the UIDBVC, you have to register which types your application uses. You do this in the Project Settings in the Info tab with your Target selected. In the Document Types area, add the types you support. Hereā€™s what it looks like to support JSON ļ¬les ā€¦ The Types ļ¬eld is the UTI of the type you want to support (e.g. public.json, public.image). The CFBundleTypeRole and LSHandlerRank say how you handle this kind of document. Are you the primary editor and owner of this type or is it just something you can open? You can add an icon for the ļ¬le type too.
  • 50. CS193p Fall 2017-18 UIDocumentBrowserViewController Declaring your own document type You might have a custom document type that your application edits You can add this under Exported UTIs in the same place in Project Settings Hereā€™s an example of adding an ā€œemojiartā€ type of document ā€¦ ā€¦ and then add it as a supported Document Type This is the ā€œUTIā€ that we keep referring to. Itā€™s like public.json is for JSON.
  • 51. CS193p Fall 2017-18 UIDocumentBrowserViewController Opening documents at the request of other apps (including Files) A user can now click on a document of your type in Files (or another app can ask to open one) When this happens, your AppDelegate gets a message sent to it ā€¦ func application(UIApplication, open: URL, options: [UIApplicationOpenURLOptionsKey:Any]) -> Bool We havenā€™t discussed the AppDelegate yet, but itā€™s just a swift ļ¬le with some methods in it. Inside here, you can ask your UIDocumentBrowserViewController to show this document ā€¦ let uidbvc = window?.rootViewController as? UIDBVC // since itā€™s ā€œarrowedā€ in storyboard uidbvc.revealDocument(at: URL, importIfNeeded: true) { (url, error) in if error != nil { // present a UIDocument at url modally (more on how to do this in a moment) } else { // handle the error } }
  • 52. CS193p Fall 2017-18 UIDocumentBrowserViewController Enabling UIDocumentBrowserViewController To make all this work, you need an entry in your Info.plist. You can add it the same way we added AppTransportSecurity (right click in Info.plist). Xcode template Luckily, an Xcode template exists to do all of the above conļ¬guration for us
  • 53. CS193p Fall 2017-18 UIDocumentBrowserViewController What is in the template? A stub for Document Types in Project Settings (supports public.image ļ¬le types) The Info.plist entry Supports Document Browser = YES The code in AppDelegate to reveal a document A stubbed out UIDocument subclass (with empty contents and load(fromContents) methods) A stubbed out MVC to display a document (just calls UIDocumentā€™s open and close methods) A subclass of UIDocumentBrowserViewController (with almost everything implemented) What you need to do ā€¦ 1. Use your UIDocument subclass instead of the stubbed out one 2. Use your document-viewing MVC code (already using UIDocument) instead of stub 3. Add code to UIDBVC subclass to ā€¦ a. conļ¬gure the UIDBVC (allow multiple selection? creation of new documents? etc.) b. specify the url of a template document to copy to create new documents c. present your document-viewing MVC modally given the url of a document 4. Update the Document Types in Project Settings to be your types (instead of public.image)
  • 54. CS193p Fall 2017-18 UIDocumentBrowserViewController Steps 1 and 2 As long as you properly implement UIDocument in your MVC, this is no extra work Step 3a: Conļ¬guring the UIDBVC This happens in its viewDidLoad ā€¦ override func viewDidLoad() { super.viewDidLoad() delegate = self // the guts of making UIDBVC work are in its delegate methods allowsDocumentCreation = true allowsPickingMultipleItems = true browserUserInterfaceStyle = .dark view.tintColor = .white } Set these as you wish.
  • 55. CS193p Fall 2017-18 UIDocumentBrowserViewController Steps 3b: Specifying the ā€œnew documentā€ template URL This happens in this UIDBVC delegate method ā€¦ func documentBrowser(_ controller: UIDBVC, didRequestDocumentCreationWithHandler handler: @escaping (URL?, UIDBVC.ImportMode) -> Void ) { let url: URL? = ā€¦ // where your blank, template document can be found importHandler(url, .copy or .move) } Usually you would specify .copy, but you could create a new template each time and .move. Likely you would have some code here that creates that blank template (or ship with your app).
  • 56. CS193p Fall 2017-18 UIDocumentBrowserViewController Aside: Presenting an MVC without segueing We havenā€™t covered how to present MVCs in any other way except by segueing. So letā€™s cover it now! Itā€™s very easy. You present a new MVC from an existing MVC using present(animated:) ā€¦ let newVC: UIViewController = ā€¦ existingVC.present(newVC, animated: true) { // completion handler called when the presentation completes animating // (can be left out entirely if you donā€™t need to do anything upon completion) } The real trick is ā€œwhere do I get newMVC from?ā€ Answer: you get it from your storyboard using its identiļ¬er which you set in Identity Inspector let storyboard = UIStoryboard(name: ā€œMainā€, bundle: nil) // Main.storyboard if let newVC = storyboard.instantiateViewController(withIdentifier: ā€œfooā€) as? MyDocVC { // ā€œprepareā€ newMVC and then present(animated:) it }
  • 57. CS193p Fall 2017-18 UIDocumentBrowserViewController Steps 3c: Presenting your document MVC modally The Xcode template stubs out a function called presentDocument(at: URL) to do this ā€¦ func presentDocument(at url: URL) { let story = UIStoryboard(name: ā€œMainā€, bundle: nil) if let docvc = story.instantiateViewController(withIdentifier: ā€œDocVCā€) as? DocVC { docvc.document = MyDocument(fileURL: url) present(docvc, animated: true) } } You can call this function anything you want. But the point is that it takes a URL to one of your documents and you show it. The Xcode template then calls this from the appropriate delegate methods in UIDBVC. Thatā€™s all you have to do to get UIDBVC working.
  • 58. CS193p Fall 2017-18 UIDocumentBrowserViewController Step 4: Specifying your types Unless your app opens public.image ļ¬les, youā€™ll need to change that in Project Settings For your homework, for example, youā€™ll probably need to invent a new type for Image Gallery
  • 59. CS193p Fall 2017-18 Demo Code Download the demo code from todayā€™s lecture.