I have a UIView subclass which contains the following:
class someClass: UIView {
var someString = ""
var imageView: UIImageView
var position: CGPoint
var dimensions: CGFloat
init(position: CGPoint, dimensions: CGFloat, someString: String) {
self.position = position
self.dimensions = dimensions
self.someString = someString
self.imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: dimensions, height: dimensions))
super.init(frame: CGRect(x: position.x, y: position.y, width: dimensions, height: dimensions))
addSubview(imageView)
}
}
Also I added required init?(coder aDecoder: NSCoder)
and encodeWithCoder(coder: NSCoder)
:
required init?(coder aDecoder: NSCoder) {
self.someString = aDecoder.decodeObject(forKey: "someString") as! String
self.position = aDecoder.decodeObject(forKey: "position") as! CGPoint
self.dimensions = aDecoder.decodeObject(forKey: "dimensions") as! CGFloat
self.imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: dimensions, height: dimensions))
super.init(frame: CGRect(x: position.x, y: position.y, width: dimensions, height: dimensions))
self.addSubview(imageView)
}
func encodeWithCoder(coder: NSCoder) {
coder.encode(self.position, forKey: "position")
coder.encode(self.dimensions, forKey: "dimensions")
coder.encode(self.someString, forKey: "someString")
}
So, I created an object of the class:
let someObject = someClass(position: CGPoint(x: 2.0, y: 3.0), dimensions: 10.0, someString: "Hello")
I'm trying to archive the object:
let archivedObject = NSKeyedArchiver.archivedData(withRootObject: someObject)
And then to unarchive:
let unarchivedObject = NSKeyedUnarchiver.unarchiveObject(with: archivedObject) as! someClass
Here I'm getting the error:
If print unarchivedObject it will be "fatal error: unexpectedly found nil while unwrapping an Optional value".
Can somebody help me with this? What is wrong?
It looks like the problem is that you're not properly overriding encodeWithEncoder
. If you put a breakpoint inside that function, you'll see that it's never getting called, which is why the object is nil when you try to decode it - it never got encoded!
You'll also run into an error trying to use decodeObject
on a CGPoint. Make sure to change that line too and then you should be in business.
By the way, it is common practice to capitalize class names so that they are distinct from instances of that class, so I changed someClass
to SomeClass
.
class SomeClass: UIView {
var someString = ""
var imageView: UIImageView
var position: CGPoint
var dimensions: CGFloat
init(position: CGPoint, dimensions: CGFloat, someString: String) {
self.position = position
self.dimensions = dimensions
self.someString = someString
self.imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: dimensions, height: dimensions))
super.init(frame: CGRect(x: position.x, y: position.y, width: dimensions, height: dimensions))
addSubview(imageView)
}
required init?(coder aDecoder: NSCoder) {
self.someString = aDecoder.decodeObject(forKey: "someString") as! String
self.position = aDecoder.decodeCGPoint(forKey: "position")
self.dimensions = aDecoder.decodeObject(forKey: "dimensions") as! CGFloat
self.imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: dimensions, height: dimensions))
super.init(frame: CGRect(x: position.x, y: position.y, width: dimensions, height: dimensions))
self.addSubview(imageView)
}
override func encode(with aCoder: NSCoder) {
aCoder.encode(self.position, forKey: "position")
aCoder.encode(self.dimensions, forKey: "dimensions")
aCoder.encode(self.someString, forKey: "someString")
}
}