When i'm trying to run the int(coder:) it shows this error, i don't know why ?? "Non failable initializer requirement init(coder:) cannot be satisfied by a failable initalizer ('init?')"
class Note: NSObject, NSCoding {
var name: String
var photo: UIImage?
var rating: Int
static let DocumentsDirectory: AnyObject = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("notes")
struct PropertyKey {
static let nameKey = "name"
static let photoKey = "photo"
static let ratingKey = "rating"
}
init?(name: String, photo: UIImage?, rating: Int) {
self.name = name
self.photo = photo
self.rating = rating
super.init()
// Initialization should fail if there is no name or if the rating is negative.
if name.isEmpty || rating < 0 {
return nil
}
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: PropertyKey.nameKey)
aCoder.encodeObject(photo, forKey: PropertyKey.photoKey)
aCoder.encodeInteger(rating, forKey: PropertyKey.ratingKey)
}
required convenience init?(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
// Because photo is an optional property of Meal, use conditional cast.
let photo = aDecoder.decodeObjectForKey(PropertyKey.photoKey) as? UIImage
let rating = aDecoder.decodeIntegerForKey(PropertyKey.ratingKey)
// Must call designated initializer.
self.init(name: name, photo: photo, rating: rating)
}
}
i'm using xcode 6 , and by the way when this code runs in xcode 7 it do not show any errors , what is the reason ?
So I found a way to make it work, the 'init(coder:)' method can't be failable so what I did was override the 'init()' method to be called by the 'init(coder:)' method because it needs to call 'self.init()'. So here is the code:
class Meal: NSObject, NSCoding {
// MARK: Archiving Paths
static let DocumentsDirectory = NSFileManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first!
static let ArchiveURL = DocumentsDirectory.URLByAppendingPathComponent("meals")
// MARK: Properties
var name: String
var rating: Int
var photo: UIImage?
// MARK: Types
struct PropertyKey {
static let nameKey = "name"
static let photoKey = "photo"
static let ratingKey = "rating"
}
// MARK: Initialization
init? (name: String, rating: Int, photo: UIImage?) {
// Intialize stored properties.
self.name = name
self.rating = rating
self.photo = photo
super.init()
// Initialization should fail if there is no name or if the rating is negative.
if self.name.isEmpty || (rating < 0) {
return nil
}
}
override private init () {
self.name = ""
self.rating = 0
self.photo = nil
}
// MARK: NSCoding
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: PropertyKey.nameKey)
aCoder.encodeObject(self.photo, forKey: PropertyKey.photoKey)
aCoder.encodeObject(self.rating, forKey: PropertyKey.ratingKey)
}
convenience required init(coder aDecoder: NSCoder) {
self.init()
let name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
if let rating = aDecoder.decodeIntegerForKey(PropertyKey.ratingKey) {
self.rating = rating
}
// Because photo is an optional property of Meal, use conditional cast.
let photo = aDecoder.decodeObjectForKey(PropertyKey.photoKey) as? UIImage
self.name = name
self.photo = photo
}
}
I made the 'init()' method private so that only methods inside the class can call it. I also had to optional unwrap the rating because the app was crashing complaining about not being able to unarchive Int with the ratingKey.
Speculation on my part as to specifics, but, generally - the precise syntax and semantics of Swift changed significantly between Xcode 6 (say, Xcode 6.4) and the new Xcode 7 betas. Xcode 6.4 supports / uses Swift language version 1.2; Xcode 7 uses Swift language version 2.0 (beta)
Found a solution to run above code in xcode6 , should remove "convenience" from the init(coder aDecoder) and use super.init() instead of self.init(name: name, photo: photo, rating: rating) then it works perfectly
class Note: NSObject, NSCoding {
var name: String
var photo: UIImage?
var rating: Int
struct PropertyKey {
static let nameKey = "name"
static let photoKey = "photo"
static let ratingKey = "rating"
}
init(name: String, photo: UIImage?, rating: Int) {
self.name = name
self.photo = photo
self.rating = rating
super.init()
// Initialization should fail if there is no name or if the rating is negative.
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(name, forKey: PropertyKey.nameKey)
aCoder.encodeObject(photo, forKey: PropertyKey.photoKey)
aCoder.encodeInteger(rating, forKey: PropertyKey.ratingKey)
}
required init(coder aDecoder: NSCoder) {
self.name = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
// Because photo is an optional property of Meal, use conditional cast.
self.photo = aDecoder.decodeObjectForKey(PropertyKey.photoKey) as? UIImage
self.rating = aDecoder.decodeIntegerForKey(PropertyKey.ratingKey) as Int
// Must call designated initializer.
super.init()
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.