encodeWithCoder unrecognized selector sent to instance - ios

I am getting this exception but I can't figure out where I'm going wrong. I am writing an extension to attempt to save this struct from the NewsAPISwiftLibrary to NSUserDefaults: NewsAPISource
This is the code to my extension:
extension NewsAPISource {
init?(data: NSData) {
if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding {
id = coding.id
name = coding.name
sourceDescription = coding.sourceDescription
url = coding.url
category = coding.category
language = coding.language
country = coding.country
sortBysAvailable = coding.sortBysAvailable as [SortBy]
} else {
return nil
}
}
func encode() -> NSData {
return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData
}
private class Encoding: NSObject, NSCoding {
let id: SourceId?
let name: String?
let sourceDescription: String?
let url: String?
let category: NewsAPISwift.Category?
let language: Language?
let country: Country?
let sortBysAvailable: [SortBy]
init(_ source: NewsAPISource) {
id = source.id
name = source.name
sourceDescription = source.sourceDescription
url = source.url
category = source.category
language = source.language
country = source.country
sortBysAvailable = source.sortBysAvailable
}
required init?(coder aDecoder: NSCoder) {
id = aDecoder.decodeObject(forKey: "id") as? SourceId
name = aDecoder.decodeObject(forKey: "name") as? String
sourceDescription = aDecoder.decodeObject(forKey:"sourceDescription") as? String
url = aDecoder.decodeObject(forKey: "url") as? String
category = aDecoder.decodeObject(forKey: "category") as? NewsAPISwift.Category
language = aDecoder.decodeObject(forKey: "language") as? Language
country = aDecoder.decodeObject(forKey: "country") as? Country
if let sorts = aDecoder.decodeObject(forKey: "sortBysAvailable") as? [SortBy] {
self.sortBysAvailable = sorts
} else {
return nil
}
}
func encode(with aCoder: NSCoder) {
aCoder.encode(id, forKey: "id")
aCoder.encode(name, forKey: "name")
aCoder.encode(sourceDescription, forKey: "sourceDescription")
aCoder.encode(url, forKey: "url")
aCoder.encode(category, forKey: "category")
aCoder.encode(language, forKey: "language")
aCoder.encode(country, forKey: "country")
aCoder.encode(sortBysAvailable, forKey: "sortBysAvailable")
}
}
}
I create a new struct like this:
let emptySource = NewsAPISource(id: "nil", name: "nil", sourceDescription: "nil", url: "nil", category: .business, language: .english, country: .unitedStates, sortBysAvailable: [.top])
and attempt to encode it like this:
emptySourceArray.encode()
This is the line that causes the exception. Any ideas on what I'm doing incorrectly?
The full error is:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x60800005f4d0'

Related

How to write set of classes to document directory using NSSecureCoding and NSKeyedArchiver?

I'm having trouble archiving and/or unarchiving (not sure where the problem is, exactly) a set of custom classes from the iOS documents directory. The set is saved to disk (or at least it appears to be saved) because I can pull it from disk but I cannot unarchive it.
The model
final class BlockedUser: NSObject, NSSecureCoding {
static var supportsSecureCoding = true
let userId: String
let name: String
let date: Int
var timeIntervalFormatted: String?
init(userId: String, name: String, date: Int) {
self.userId = userId
self.name = name
self.date = date
}
required convenience init?(coder: NSCoder) {
guard let userId = coder.decodeObject(forKey: "userId") as? String,
let name = coder.decodeObject(forKey: "name") as? String,
let date = coder.decodeObject(forKey: "date") as? Int else {
return nil
}
self.init(userId: userId, name: name, date: date)
}
func encode(with coder: NSCoder) {
coder.encode(userId, forKey: "userId")
coder.encode(name, forKey: "name")
coder.encode(date, forKey: "date")
}
}
Writing to disk
let fm = FileManager.default
let dox = fm.urls(for: .documentDirectory, in: .userDomainMask)[0]
let dir = dox.appendingPathComponent("master.properties", isDirectory: true)
do {
let userData: [URL: Any] = [
/* Everything else in this dictionary is a primitive type (string, bool, etc.)
and reads and writes without problem from disk. The only thing I cannot
get to work is the entry below (the set of custom classes). */
dir.appendingPathComponent("blockedUsers", isDirectory: false): blockedUsers // of type Set<BlockedUser>
]
for entry in userData {
let data = try NSKeyedArchiver.archivedData(withRootObject: entry.value, requiringSecureCoding: true)
try data.write(to: entry.key, options: [.atomic])
}
} catch {
print(error)
}
Reading from disk
if let onDisk = try? Data(contentsOf: dir.appendingPathComponent("blockedUsers", isDirectory: false)) {
if let blockedUsers = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(onDisk) as? Set<BlockedUser> {
print("success")
} else {
print("file found but cannot unarchive") // where I'm currently at
}
} else {
print("file not found")
}
The problem is that you are trying to decode an object instead of decoding an integer. Check this post. Try like this:
class BlockedUser: NSObject, NSSecureCoding {
static var supportsSecureCoding = true
let userId, name: String
let date: Int
var timeIntervalFormatted: String?
init(userId: String, name: String, date: Int) {
self.userId = userId
self.name = name
self.date = date
}
func encode(with coder: NSCoder) {
coder.encode(userId, forKey: "userId")
coder.encode(name, forKey: "name")
coder.encode(date, forKey: "date")
coder.encode(timeIntervalFormatted, forKey: "timeIntervalFormatted")
}
required init?(coder: NSCoder) {
userId = coder.decodeObject(forKey: "userId") as? String ?? ""
name = coder.decodeObject(forKey: "name") as? String ?? ""
date = coder.decodeInteger(forKey: "date")
timeIntervalFormatted = coder.decodeObject(forKey: "timeIntervalFormatted") as? String
}
}

Swift: Unknown error - Unexpectedly found nil while unwrapping an Optional value

I know this is a common error people post here but I can't find a post that matches to what I'm doing even if its the same fundamentally. I'm new to Swift and just trying to find my way, thank you.
The first time I open my app, a blog reader app that reads from a MYSQL database, it works as intended, I can follow the blogs that I chose and unfollow. When I follow a blog/cell it saves to User Defaults using KeyArchiver but when I double tap the home button to clear the app from memory and reopen the app, it crashes.
Something wrong is going on in my loadUserDefaults because I set up breakpoints and it crashes at this line self.followedIdentifiers = Set(UserDefaults.standard.stringArray(forKey: "followedID")!)
I know I have an optional but why is it crashing/ coming back nil if I saved it with saveUserDefaults. Is it not saving? or am I not loading it correctly?
The error is this
fatal error: unexpectedly found nil while unwrapping an Optional value
Code: This is MainController.swift
var mainArray = [Blog]()
var followedArray = [Blog]()
var filteredArray = [Blog]()
var followedIdentifiers = Set<String>()
override func viewDidLoad() {
super.viewDidLoad()
// Receiving Data from Server
retrieveDataFromServer()
// NSCoding - Unarchiving Data (followedID)
loadUserDefaults()
}
// NSCoding: Archiving UserDefaults
func saveUserDefaults() {
// Saving to UserDefaults
let encodedData = NSKeyedArchiver.archivedData(withRootObject: self.followedIdentifiers)
UserDefaults.standard.setValue(encodedData, forKey: "followedID")
UserDefaults.standard.synchronize()
}
// NSCoding: Unarchiving UserDefaults
func loadUserDefaults() { // --- Crash is Here ---
// Unarchiving Data
if let data = UserDefaults.standard.data(forKey: "followedID"), let myFollowedList = NSKeyedUnarchiver.unarchiveObject(with: data) as? Set<String> {
self.followedIdentifiers = myFollowedList
self.followedIdentifiers = Set(UserDefaults.standard.stringArray(forKey: "followedID")!) // CRASH
} else {
print("Error/ Empty: (Loading UserDefaults (followedID))")
}
}
// Retrieving Data from Server
func retrieveDataFromServer() {
let getDataURL = "http://example.com/receiving.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray
// Clear the arrays
self.followedArray = [Blog]()
self.mainArray = [Blog]()
// Looping through jsonArray
for jsonObject in jsonArray {
if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {
// Check if identifiers match
if followedIdentifiers.contains(blog.blogID) {
self.followedArray.append(blog)
} else {
self.mainArray.append(blog)
}
}
}
} catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
}
This is Blog.swift which handles all the blogs objects and NSCoding
class Blog: NSObject, NSCoding {
var blogName: String
var blogStatus1: String
var blogStatus2: String
var blogURL: String
var blogID: String
var blogType: String
var blogDate: String
var blogPop: String
private init (name: String,status1: String,status2: String,url: String,id: String,type: String,date: String,pop: String) {
blogName = name
blogStatus1 = status1
blogStatus2 = status2
blogURL = url
blogID = id
blogType = type
blogDate = date
blogPop = pop
super.init()
}
convenience init?(jsonObject: [String:Any]) {
guard let bID = jsonObject["id"] as? String,
let bName = jsonObject["blogName"] as? String,
let bStatus1 = jsonObject["blogStatus1"] as? String,
let bStatus2 = jsonObject["blogStatus2"] as? String,
let bURL = jsonObject["blogURL"] as? String,
let bType = jsonObject["blogType"] as? String,
let bDate = jsonObject["blogDate"] as? String,
let bPop = jsonObject["blogPop"] as? String
else {
print("Error: (Creating Blog Object)")
return nil
}
self.init(name: bName, status1: bStatus1, status2: bStatus2, url: bURL, id: bID, type: bType, date: bDate, pop: bPop)
}
convenience required init?(coder aDecoder: NSCoder) {
guard let blogName = aDecoder.decodeObject(forKey: "blogName") as? String,
let blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as? String,
let blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as? String,
let blogURL = aDecoder.decodeObject(forKey: "blogURL") as? String,
let blogID = aDecoder.decodeObject(forKey: "blogID") as? String,
let blogType = aDecoder.decodeObject(forKey: "blogType") as? String,
let blogDate = aDecoder.decodeObject(forKey: "blogDate") as? String,
let blogPop = aDecoder.decodeObject(forKey: "blogPop") as? String else {
print("Error: (Creating Blog Object)")
return nil
}
self.init(name: blogName, status1: blogStatus1, status2: blogStatus2, url: blogURL, id: blogID, type: blogType, date: blogDate, pop: blogPop)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(blogName, forKey: "blogName")
aCoder.encode(blogStatus1, forKey: "blogStatus1")
aCoder.encode(blogStatus2, forKey: "blogStatus2")
aCoder.encode(blogURL, forKey: "blogURL")
aCoder.encode(blogID, forKey: "blogID")
aCoder.encode(blogType, forKey: "blogType")
aCoder.encode(blogDate, forKey: "blogDate")
aCoder.encode(blogPop, forKey: "blogPop")
}
}
I used File Manager to save my archived array and it was the best choice, so easy and simple. Using Swift 3. Credit to #GuyKogus, #Paulw11 & #MartinR
Used to save my object
NSKeyedArchiver.archiveRootObject(myObject, toFile: filePath)
Used to load my object
if let myFollowedList = NSKeyedUnarchiver.unarchiveObject(withFile: filePath) as? Set<String> {
myObject = myFollowedList
}

Swift: Error - Initializer for conditional binding must have Optional type, not 'Void' (aka '()')

Using Swift 3, blog reader app reading from a MYSQL database using JSON and PHP. User has the ability to save the blog they want to keep getting updates from using a follow button (as well as unfollow button). Instead of saving the entire array, just trying to save the followed blogs ID so the app just finds the blogs id and shows that specific blog that the user followed.
This is the error I'm getting when loading the user defaults
Initializer for conditional binding must have Optional type, not 'Void' (aka '()')
This error is in func loadUserDefaults() in MainController.swift at first line if let data = UserDefaults..
After the user clicks the follow button, I move the cells between arrays, between sections in the tableview and then I call saveUserDefaults()
This is MainController.swift
var mainArray = [Blog]()
var followedArray = [Blog]()
var filteredArray = [Blog]()
var followedIdentifiers = Set<String>()
override func viewDidLoad() {
super.viewDidLoad()
// Receiving Data from Server
retrieveDataFromServer()
// NSCoding - Unarchiving Data (followedID)
loadUserDefaults()
}
// NSCoding: Archiving UserDefaults
func saveUserDefaults() {
// Saving to UserDefaults
let encodedData = NSKeyedArchiver.archivedData(withRootObject: self.followedIdentifiers)
UserDefaults.standard.setValue(encodedData, forKey: "followedID")
UserDefaults.standard.synchronize()
}
// NSCoding: Unarchiving UserDefaults *** ERROR IS HERE ***
func loadUserDefaults() {
// Unarchiving Data -- ERROR: THIS FIRST LINE --
if let data = UserDefaults.standard.setValue(Array(self.followedIdentifiers), forKey: "followedID"),
let myFollowedList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Blog] {
self.followedIdentifiers = myFollowedList
self.followedIdentifiers = Set(UserDefaults.standard.stringArray(forKey: "followedID")!)
} else {
print("Error/ Empty: (Loading UserDefaults (followedID))")
}
}
// Retrieving Data from Server
func retrieveDataFromServer() {
let getDataURL = "http://example.com/receiving.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray
// Clear the arrays
self.followedArray = [Blog]()
self.mainArray = [Blog]()
// Looping through jsonArray
for jsonObject in jsonArray {
if let blog = Blog(jsonObject:jsonObject as! [String : Any]) {
// Check if identifiers match
if followedIdentifiers.contains(blog.blogID) {
self.followedArray.append(blog)
} else {
self.mainArray.append(blog)
}
}
}
} catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
}
This is Blog.swift which handles all the blogs objects and NSCoding
class Blog: NSObject, NSCoding {
var blogName: String
var blogStatus1: String
var blogStatus2: String
var blogURL: String
var blogID: String
var blogType: String
var blogDate: String
var blogPop: String
private init (name: String,status1: String,status2: String,url: String,id: String,type: String,date: String,pop: String) {
blogName = name
blogStatus1 = status1
blogStatus2 = status2
blogURL = url
blogID = id
blogType = type
blogDate = date
blogPop = pop
super.init()
}
convenience init?(jsonObject: [String:Any]) {
guard let bID = jsonObject["id"] as? String,
let bName = jsonObject["blogName"] as? String,
let bStatus1 = jsonObject["blogStatus1"] as? String,
let bStatus2 = jsonObject["blogStatus2"] as? String,
let bURL = jsonObject["blogURL"] as? String,
let bType = jsonObject["blogType"] as? String,
let bDate = jsonObject["blogDate"] as? String,
let bPop = jsonObject["blogPop"] as? String
else {
print("Error: (Creating Blog Object)")
return nil
}
self.init(name: bName, status1: bStatus1, status2: bStatus2, url: bURL, id: bID, type: bType, date: bDate, pop: bPop)
}
convenience required init?(coder aDecoder: NSCoder) {
guard let blogName = aDecoder.decodeObject(forKey: "blogName") as? String,
let blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as? String,
let blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as? String,
let blogURL = aDecoder.decodeObject(forKey: "blogURL") as? String,
let blogID = aDecoder.decodeObject(forKey: "blogID") as? String,
let blogType = aDecoder.decodeObject(forKey: "blogType") as? String,
let blogDate = aDecoder.decodeObject(forKey: "blogDate") as? String,
let blogPop = aDecoder.decodeObject(forKey: "blogPop") as? String else {
print("Error: (Creating Blog Object)")
return nil
}
self.init(name: blogName, status1: blogStatus1, status2: blogStatus2, url: blogURL, id: blogID, type: blogType, date: blogDate, pop: blogPop)
}
func encode(with aCoder: NSCoder) {
aCoder.encode(blogName, forKey: "blogName")
aCoder.encode(blogStatus1, forKey: "blogStatus1")
aCoder.encode(blogStatus2, forKey: "blogStatus2")
aCoder.encode(blogURL, forKey: "blogURL")
aCoder.encode(blogID, forKey: "blogID")
aCoder.encode(blogType, forKey: "blogType")
aCoder.encode(blogDate, forKey: "blogDate")
aCoder.encode(blogPop, forKey: "blogPop")
}
}
The line of code:
let data = UserDefaults.standard.setValue(Array(self.followedIdentifiers), forKey: "followedID")
makes no sense since setValue method doesn't return any values.
Looks like you need to replace it with (Swift 3):
let data = UserDefaults.standard.data(forKey: "followedID")
Updated with #closetCoder comment
The setValue function is a void function so it can't be assigned to the variable data since it has no return value.
Here is the documentation for UserDefaults from Apple: https://developer.apple.com/documentation/foundation/userdefaults

Swift: self.init (coder : aDecoder) is crashing app with EXC_BAD_ACCESS

Error is crashing app when using NSCoder and NSKeyArchiver.
I had made a recent post around NSCoder but since then I've changed my code around and got a new error and decided a new post is best.
The app is a blog reader, reading from a MYSQL database using PHP to fill a table view with custom objects in Swift using JSON. I've been trying to save mainArray so that when the user moves cells across sections (each section has an array) it can save where the user left it.
Blog.swift: Handles the Blogs custom objects
import UIKit
class Blog: NSObject, NSCoding {
var blogName: String!
var blogStatus1: String!
var blogStatus2: String!
var blogURL: String!
var blogID: String!
var blogType: String!
var blogDate: String!
var blogPop: String!
static func createBlog(from jsonObject: AnyObject) -> Blog? {
guard let bID: String = jsonObject.object(forKey: "id") as? String,
let bName: String = jsonObject.object(forKey: "blogName") as? String,
let bStatus1: String = jsonObject.object(forKey: "blogStatus1") as? String,
let bStatus2: String = jsonObject.object(forKey: "blogStatus2") as? String,
let bURL: String = jsonObject.object(forKey: "blogURL") as? String,
let bType: String = jsonObject.object(forKey: "blogType") as? String,
let bDate: String = jsonObject.object(forKey: "blogDate") as? String,
let bPop: String = jsonObject.object(forKey: "blogPop") as? String
else {
print("Error: (Creating Blog Object)")
return nil
}
let blog = Blog()
blog.blogName = bName
blog.blogStatus1 = bStatus1
blog.blogStatus2 = bStatus2
blog.blogURL = bURL
blog.blogID = bID
blog.blogType = bType
blog.blogDate = bDate
blog.blogPop = bPop
return blog
}
// NSCoding
convenience required init?(coder aDecoder: NSCoder) {
self.init (coder : aDecoder) // *** Crashes Here ***
self.blogName = aDecoder.decodeObject(forKey: "blogName") as! String
self.blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as! String
self.blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as! String
self.blogURL = aDecoder.decodeObject(forKey: "blogURL") as! String
self.blogID = aDecoder.decodeObject(forKey: "blogID") as! String
self.blogType = aDecoder.decodeObject(forKey: "blogType") as! String
self.blogDate = aDecoder.decodeObject(forKey: "blogDate") as! String
self.blogPop = aDecoder.decodeObject(forKey: "blogPop") as! String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(blogName, forKey: "blogName")
aCoder.encode(blogStatus1, forKey: "blogStatus1")
aCoder.encode(blogStatus2, forKey: "blogStatus2")
aCoder.encode(blogURL, forKey: "blogURL")
aCoder.encode(blogID, forKey: "blogID")
aCoder.encode(blogType, forKey: "blogType")
aCoder.encode(blogDate, forKey: "blogDate")
aCoder.encode(blogPop, forKey: "blogPop")
}
}
MainController.swift - Where table view is located
var mainArray = [Blog]()
var followedArray = [Blog]()
override func viewDidLoad() {
super.viewDidLoad()
// Receiving Data from Server
retrieveData()
if let data = UserDefaults.standard.data(forKey: "mainArrayKey"),
let myBlogList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Blog] {
mainArray = myBlogList
print("mainArray: \(mainArray)")
} else {
print("Error: (Saving to UserDefaults)")
}
}
// Retrieving Data from Server
func retrieveData() {
let getDataURL = "http://example.com/receiving.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray
// Looping through jsonArray
for jsonObject in jsonArray {
if let blog = Blog.createBlog(from: jsonObject as AnyObject) {
mainArray.append(blog)
// Save to UserDefaults
let encodedData = NSKeyedArchiver.archivedData(withRootObject: mainArray)
UserDefaults.standard.set(encodedData, forKey: "mainArrayKey")
}
}
}
catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
// Logs
print("This is mainArray", mainArray)
// Check UserDefaults
if UserDefaults.standard.object(forKey: "mainArrayKey") != nil{
print("mainArray key exists")
}
else {
print("mainArray key does not exist")
}
}
Looks like an infinite loop to me. You call init(coder:), and the first line calls init(coder:), and the first line calls init(coder:), and so on ad infinitum.
You need to call a different initializer inside it. Try self.init() instead.
As others have stated it's indeed an infinite loop. What you need to do is change it to self.init() and also add in the following to your code. Or implement your own init that does whatever needs to be done.
override init() {
super.init()
}

Saving array using NSUserDefaults crashes app

I feel as if I am doing things correctly, but I am getting an error at the end of my data conversion and retrieval. Please see the code below:
class Task:NSObject, NSCoding {
var name:String
var notes:String
var date:NSDate
var taskCompleted:Bool
init(name:String, notes:String,date:NSDate, taskCompleted:Bool){
self.name = name
self.notes = notes
self.date = date
self.taskCompleted = taskCompleted
}
required init(coder decoder: NSCoder){
self.name = (decoder.decodeObjectForKey("name") as! String?)!
self.notes = (decoder.decodeObjectForKey("notes") as! String?)!
self.date = (decoder.decodeObjectForKey("date") as! NSDate?)!
self.taskCompleted = (decoder.decodeObjectForKey("taskCompleted") as! Bool?)!
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(self.name, forKey: "name")
coder.encodeObject(self.notes, forKey: "notes")
coder.encodeObject(self.date, forKey: "date")
coder.encodeObject(self.taskCompleted, forKey: "taskCompleted")
}
}
I then save and get the data as follows:
let nowData = NSKeyedArchiver.archivedDataWithRootObject([nowTasks])
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(nowData, forKey: "nowData")
let loadedData = defaults.dataForKey("nowData")
let loadedArray = NSKeyedUnarchiver.unarchiveObjectWithData(loadedData!) as! [Task]
When I call print(loadedArray.first) I get the error: NSArray element failed to match the Swift Array Element type
Looks like your code should work fine even with some really weird forced casting going on in your decoder method. Try like this:
class Task: NSObject, NSCoding {
var name = String()
var notes = String()
var date: NSDate
var taskCompleted: Bool
init(name: String, notes: String, date: NSDate, taskCompleted: Bool){
self.name = name
self.notes = notes
self.date = date
self.taskCompleted = taskCompleted
}
required init(coder decoder: NSCoder){
self.name = decoder.decodeObjectForKey("name") as! String
self.notes = decoder.decodeObjectForKey("notes") as! String
self.date = decoder.decodeObjectForKey("date") as! NSDate
self.taskCompleted = decoder.decodeBoolForKey("taskCompleted")
}
func encodeWithCoder(coder: NSCoder) {
coder.encodeObject(name, forKey: "name")
coder.encodeObject(notes, forKey: "notes")
coder.encodeObject(date, forKey: "date")
coder.encodeBool(taskCompleted, forKey: "taskCompleted")
}
}
Testing with plist files:
let task1 = Task(name: "task1", notes: "note a", date: NSDate(), taskCompleted: false)
let task2 = Task(name: "task2", notes: "note b", date: NSDate(), taskCompleted: true)
let documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
let fileURL = documentsDirectory.URLByAppendingPathComponent("data.plist")
if let filePath = fileURL.path {
NSKeyedArchiver.archiveRootObject([task1,task2], toFile: filePath)
if let loadedArray = NSKeyedUnarchiver.unarchiveObjectWithFile(filePath) as? [Task] {
print(loadedArray.count)
print(loadedArray.first?.name ?? "")
print(loadedArray.first?.notes ?? "")
print(loadedArray.first!.date )
print(loadedArray.first!.taskCompleted)
print(loadedArray.last?.name ?? "")
print(loadedArray.last?.notes ?? "")
print(loadedArray.last!.date )
print(loadedArray.last!.taskCompleted)
}
}

Resources