Variable is not nil but code thinks it's nil - ios

I have a class that implements a protocol in order to add 3 variables. I specifically set the image variable, debugger show that the variable exist, but in code when I print it it shows nil, my if let statement also thinks the variable is nil.
#objc protocol DashboardItem {
var title: String { get }
var detail: String { get }
optional var image: UIImage { get }
}
class StaticDashboardItem: DashboardItem {
var title: String
var detail: String
var image: UIImage?
init(title: String, detail: String, image: UIImage) {
self.title = title
self.detail = detail
self.image = image
}
}
EDIT: New screenshot
Logs
nil
2

Your StaticDashboardItem does not fully implement your DashboardItem protocol. It conforms to it but does not implement the var image: UIImage { get } variable, which he has every right not to implement because this conformance is optional. So your StaticDashboardItem does not have any property/variable image that is coming from that protocol.
BUT, instead, you have added another, completely unrelated property var image: UIImage? to your StaticDashboardItem, and you unfortunately gave it the same named, hence your confusion. But that property image on your StaticDashboardItem is not the same as the one from your DashboardItem protocol and that's where your confusion comes from.
If that var image: UIImage? from your StaticDashboardItem is intended to be the implementation of that non-mandatory image property from your protocol then the types must match, so that property from your StaticDashboardItem must be of type UIImage, not UIImage?.
If that var image: UIImage? from your StaticDashboardItem is intended to be a completely different property unrelated to your protocol, then you better use a different name to avoid confusion.
[EDIT] Now that you've updated your question to show more code that confirms my assumptions. As your local dashboardItem parameter in your configure method is declared as a DashboardItem (so, the protocol), then dashboardItem.image refers to the protocol's property (as that code doesn't know about StaticDashboardItem of course, it only know the protocol), which in your case does not exist (you have no property named image of type UIImage in that dashboardItem you're introspecting) explaining that println result nil and that else branch being executed, that's all to be expected given your code.
The only thing that misleads you is the debugger tooltip that also shows you avery other properties of the object being inspected, even properties not limited to the ones from your DashboardItem protocol type, so including that image: UIImage? property and any other coming from the StaticDashboardItem real type of your object.

You are being misled by the way the debugger works. In your screen shot, we are paused before the variable whose value you are examining. Thus, your tool tip showing the value of dashboardItem is not necessarily accurate. The value of dashboardItem is valid for lines before the line where we are paused, not for lines after the line where we are paused.

Related

Determining from Objective-c if a Swift property is declared as dynamic

I have been trying for some time to inspect a Swift class, and determine if any of the properties are declared as dynamic. My example class is as below:
class SwiftTestClass : DBObject {
dynamic var SwiftTestString : String!
dynamic var SwiftTestNumber : NSNumber!
dynamic var lowercaseField : String!
var nonDynamicVariable : String!
func testThyself() {
SwiftTestClass.query().fetchLightweight().removeAll()
let newObject = SwiftTestClass();
newObject.SwiftTestString = "hello, world"
newObject.SwiftTestNumber = 123
newObject.lowercaseField = "lowercase"
newObject.nonDynamicVariable = "should not be persisted"
newObject.commit()
let result = SwiftTestClass.query().fetch().firstObject;
print(result)
}
}
I am basically trying to pick out the fact that the property nonDynamicVariable is not declared as dynamic as the rest of them are.
DBObject is a subclass of NSObject.
I have tried:
Looking at the type encoding of the property, they are identical (type for type)
Seeing if they have a difference in the method implementations, they do not. (e.g. class_getMethod), the dynamic properties still have getter/setter methods.
Grabbing the Ivars to see if there is any difference there
Looking at all of the property attributes, also identical.
What I do know:
If I try to class_replaceMethod for the <propertyName>/set<propertyName>, it works for a dynamic property (as you would expect, because it adds objc compatibility) but fails to work (but does replace?, well, the memory address of the method changes!) or be actioned on the non dynamic property.
Does anyone know how to differentiate the two property declarations in swift from objc?
Thanks

initializing class properties before use in Swift/iOS

I'm having trouble grasping the proper way of instantiating variables that always need to be set before an object is fully functional but may need to be instantiated after the constructor. Based on Swift's other conventions and restrictions it seems like there is a design pattern I'm unaware of.
Here is my use case:
I have a class that inherits from UIViewController and will programmatically create views based on user actions
I need to attach these views to this class, but to do so I need to retrieve their content based on configuration data supplied by another controller
I don't care if this configuration data is passed to the constructor (in which case it would always be required) or supplied by a secondary call to this object before it is used
My problem seems to be that both of the approaches in bullet 3 seem flawed.
In the first case, there is only one legitimate constructor this class can be called with, yet I'm forced to override other constructors and initialize member variables with fake values even if the other constructors are never intended to be used (I'm also trying to keep these variables as let types based on Swift's best practices).
In the second case, I'm effectively splitting my constructor into two parts and introduce an additional point of failure in case the second part fails to be called prior to class being used. I also can't move this second part to a method that's guaranteed to be called prior to usage (such as viewDidLoad) because I still need to pass in additional arguments from the config. While I can make sure to call the initPartTwo manually, I'd prefer to have a mechanism that better groups it with the actual constructor. I can't be the first one to run into this and it seems like there is a pattern I'm not seeing to make this cleaner.
UPDATE:
I ended up going with a modified version of the pattern matt suggested:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
If an initial instance variable property value can't be supplied at object initialization time, the usual thing is to declare it as an Optional. That way it doesn't need to be initialized by the class's initializers (it has a value - it is nil automatically), plus your code subsequently can distinguished uninitialized (nil) from initialized (not nil).
If the Optional if an implicitly unwrapped Optional, this arrangement need have no particular effect on your code (i.e. it won't have to be peppered with unwrappings).
If your objection is that you are forced to open the door to multiple settings of this instance variable because now it must be declared with var, then close the door with a setter observer:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash

How do I determine whether a UIImage is empty?

How do I check to see if a UIImage is empty?
class UserData {
...
var photo: UIImage = UIImage()
}
My ViewController code looks like:
var userData = UserData()
...
func preparePhoto(){
if (self.userData.photo == nil) {
...
}else{
...
}
}
self.userData.photo == nil won't work in Swift.
Xcode says: UIImage is not convertible to MirrorDisposition
self.userData.photo will never be nil, so the question is pointless.
The reason is that you have declared photo as a UIImage. That is not the same as a UIImage? - an Optional wrapping a UIImage. Only an Optional can be nil in Swift. But, as I just said, photo is not an Optional. Therefore there is nothing to check. That is why Swift stops you when you try to perform such a check.
So, what to do? I have two possible suggestions:
My actual recommendation for solving this is that you do type photo as a UIImage? and set it initially to nil (actually, it is implicitly nil from the start). Now you can check for nil to see whether an actual image has been assigned to it.
But keep in mind that you then will have to remember to unwrap photo when you want to use it for anything! (You could instead type photo as an implicitly unwrapped optional, UIImage!, to avoid that constant unwrapping, but I am not as keen on that idea.)
An alternative possibility would be to examine the size of the image. If it is zero size, it is probably an empty image in the original sense of your question!

Swift - casting a nil core data string as an optional value

I have a field stored on a core data object called "metadata" which is of type String (no optional, because Apple docs say not to mess with optionals in CD). Sometimes, the metadata field is nil. In checking whether this value is nil, I do the following check:
if object.metadata as String? != nil {
...
}
However, my code continuously crashes on this line as an EXC_BAD_ACCESS. I have also tried:
if let metadata = object.metadata as String? {
...
}
Which doesn't work either. I cast objects successfully to optionals in other parts of my code, so I don't understand why this particular case isn't working. How do you check whether a core data property is a nil string?
It looks like what you really want is this:
if object.metadata != nil {
...
}
or this:
if let metadata = object.metadata as? String {
// You can now freely access metadata as a non-optional
...
}
--EDIT--
My mistake, I didn't read the first part of your question thoroughly enough. It looks like the duplicate answer has a solution for this. Essentially, the generated managed object subclass is a bug and you should modify the properties to be either optional or implicitly unwrapped. You can check both of those using the first method for implicitly unwrapped and second for optionals.
There are several questions which discuss the issue of the generated subclasses not producing optional properties. I wouldn't be too concerned about editing the subclasses; there's nothing special about them except that Apple is making it easier to create them.
Check if property is set in Core Data?
Swift + CoreData: Cannot Automatically Set Optional Attribute On Generated NSManagedObject Subclass
--Edit2--
If you really don't want to touch the subclass you can access the property using valueForKey() and could add that as an extension if you wanted something a bit cleaner.
if let metadata = object.valueForKey("metadata") as String? {
...
}
In an extension:
extension ObjectClass {
var realMetadata: String? {
set {
self.setValue(newValue, forKey: "metadata")
}
get {
return self.valueForKey("metadata") as String?
}
}
}

Cannot convert the expression type of AnyObject? to type '$T3'

i am trying to get an imageview by passing image in Swift. But i got an error.
func setImageViewForImage(image:UIImage) -> UIImageView?{
var image_pmc:UIImage = image
var imageView_pmc:UIImageView = UIImageView(image: image_pmc)
imageView_pmc.frame = CGRectMake(self.frame.size.width/2 - image_pmc.size.width/2, 10, image_pmc.size.width, image_pmc.size.height)
return imageView_pmc
}
function call:
var imgView = setImageViewForImage(response) //error
//response is UIImage
The error is because your response variable is of AnyObject? type, which cannot be implicitly cast to UIImage, and however, being an optional, it must be unwrapped before passing to setImageViewForImage (which expects a non optional).
You should use optional binding combined with optional downcast as follows:
if let response = response as? UIImage {
myClass.setImageViewForImage(response)
}
where myClass is an instance of the class containing the setImageViewForImage method - presumably an instance of (a subclass of) UIView.
Note that I am making the assumption that response actually contains an UIImage - its name makes me think it's something you receive from a REST API call or similar.
Note that avoiding the optional binding and using explicit cast:
myClass.setImageViewForImage(response as UIImage)
is not safe because if response is nil or it doesn't contain a UIImage instance, the app will most likely crash.

Resources