Reputation: 7434
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 ?
Upvotes: 1
Views: 5796
Reputation: 21
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.
Upvotes: 2
Reputation: 7434
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()
}
}
Upvotes: 0
Reputation: 304
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)
Upvotes: 0