Swift: why does inheriting from NSManagedObject ruin my properties? - ios

I'm a total Swift/IOS newbie and there's something about CoreData that I simply can't understand.
I have a class with some non-optional properties that are initialized by a designated initializer. Then, if I set that class to inherit from NSManagedObject, then suddenly I get the error
Stored property X requires an initial value or should be #NSManaged.
Why does Swift suddenly think my properties are not initialized, even though they clearly are?
Also, I read that #NSManaged "tells the compiler that the storage and implementation of the properties will be handled by CoreData", but what does that even mean?
Any answers would be appreciated..

I was actually just reading about this yesterday.
Yes, it kinda really acts like #dynamic -- technically it might be
identical even. Semantically there is a slight difference:
#dynamic says 'compiler, don't check if my properties are also
implemented. There might be no code you can see but I guarantee it
will work at runtime'
#NSManaged now says 'compiler, don't check those properties as I have
Core Data to take care of the implementation - it will be there at
runtime'
so you could even say: #NSManaged is syntactic sugar that is a more
narrow version of dynamic :)
taken from this question
The big push with swift was to make the language extremely safe, as in this case, checking if the properties are implemented at compile time. If I understand correctly, CoreData doesn't quite conform to these compile time checks, thus adding in #NSManaged lets the compilers know that the variables will be taken care of.
From Apple:
You use the #NSManaged attribute to inform the Swift compiler that
Core Data provides the storage and implementation of a declaration at
runtime.

Related

How to represent Core Data optional Scalars (Bool/Int/Double/Float) in Swift?

(first noticed on: Xcode 8.2.1, iOS 10, Swift 3)
(still present as of: Xcode 9 beta 3, iOS11, Swift 4)
We all know that the Core Data concept of optionals precedes and is not strictly tied to the Swift concept of optionals.
And we have accepted that even if a Core Data attribute is marked as Non-optional, the auto-generated NSManagedObject subclass has an optional type:
(some people manually remove the ? with no adverse effects, some don't, but that's beside the point)
(From here on the example and screenshots are for Bool properties, but same goes for Int16/32/64, Double, Float)
Now I noticed the reverse - when a Core Data attribute of type Bool is marked as Optional (and Use Scalar Type is chosen, which Xcode does by default), the auto-generated class has a variable of a non-optional type.
Does this make sense? Is it a bug? Is the behaviour documented anywhere?
And most importantly - how do I actually represent an optional Bool?
I can think of some work-arounds, but they don't seem ideal (e.g. not using scalars, but going back to NSNumber representation of the Bool. Or (even worse) having a separate Bool called something like isVerified_isSet)
Note: I did a couple more tests and if the Default Value is set to None or to NO, then the variable gets saved as false (even if I never actually assign it in my code). If the Default Value is set to YES, then the variable gets saved as true. Still, this means that (apparently) there is no way to logically represent this variable as not having been set yet.
I see the same thing, and I consider it to be a bug. It's not documented anywhere that I can find. Apparently Core Data is applying Objective-C style assumptions here, where a boolean defaults to NO, and an integer defaults to 0. The Core Data/Swift interface has some rough edges, and this is one I hadn't considered before.
It's a good find but I think you're stuck with it until Apple addresses it. You already know the best workarounds, which I agree aren't great. I recommend filing a bug.
This happens because Objective-C scalar types do not have a notion of nil value. Source: handling-core-data-optional-scalar-attributes
I would rather use Objective-C types to manage these cases than Swift types.
In these cases, for scalars types, you can use NSNumber.
#NSManaged public var myDouble: NSNumber?
In the model myDouble is an optional double with nil value by default.
To get the real value you only need to use:
myEntity.myDouble?.doubleValue
If you end up here with this:
#NSManaged var boolAttribute: Bool
and it is not being seen in Objective-C, and you have already disabled "Optional" and enabled "Use Scalar Type" on those attributes, then do yourself a favour.
Double check you have imported your Swift bridging header into that Objective-C file.
I did not and, well, I was most of the way to changing my Bools to NSNumbers before smacking my head and realising how foolish I had been.

Cannot assign a value of type 'AnyDataSource<NSManagedObjectSubclass>' to a value of type 'AnyDataSource<NSManagedObject>'

I'm stumped.
The title of this question the compiler error.
I am creating an object that basically marries the delegates of NSFetchedResultsController and UITableViewDataSource. The type parameter is used to indicate which NSManagedObject subclass should be used in the fetch requests.
Here is an example where Swift lacks dynamism and we end up writing all sorts of crazy code, (OR, I'm new to Swift and dislike being told what I'm not allowed to do)
So, on a UITableViewController subclass, i'd like to have a property
var dataSource: AnyDataSource<NSManagedObject>?
when I try to create one of these with a subclass of NSManagedObject and assign it to that property, the compiler complains. There seems to be nothing I can do that will succeed without a warning.
You would think that I should be able to use NSManagedObject or any of its subclasses, so I'm a little confused.
Any ideas? I'm using typical "type erasure" patterns that can be found on the internet, like via realm.io.
Ultimately I found that this approach was not possible. I mean, to achieve these with completely protocol-based programming.
I defined a few base protocols with no associated type, implemented an abstract baseclass that implements that protocol, then introduced generic type parameters in subclasses, that implement further protocols that have associated type.
I'll post my generalized solution on github when it's finished.

What does #NSManaged do?

I have encountered this keyword in various occasions. I kind of know what it's suppose to do. But I really want a better understanding of it.
What I noticed about #NSManaged - based not on documentation, but through repeated use:
It magically replaces key value coding.
It is roughly equivalent to #dynamic in Objective-C (which I don't know much about)
I need it to subclass PFObject from the Parse SDK. It normally uses KVC to read/write values from/to the backend.
Prefixing any variable with #NSManaged will shut the compiler up when I don't initialize within the initializer.
The formal definition (in the Core Data Apple Docs):
Core Data provides the underlying storage and implementation of properties in subclasses of the NSManagedObject class. Add the #NSManaged attribute before each property definition in your managed object subclass that corresponds to an attribute or relationship in your Core Data model. Like the #dynamic attribute in Objective-C, the #NSManaged attribute informs the Swift compiler that the storage and implementation of a property will be provided at runtime. However, unlike #dynamic, the #NSManaged attribute is available only for Core Data support.
What I got from that:
Variables with #NSManaged shall be exempt from compile time checks for something.
I've read the formal documentation and various other SO questions regarding this matter:
#synthesize vs #dynamic, what are the differences?
What is common case for #dynamic usage?
I instinctively recognize some scenarios where I should use it. I partially know what it does. But what I seek is purer understanding of what it does.
Further Observations:
A PFObject in the Parse SDK relies on Key Value Coding to access its values. The PFObject provides the following accessors:
objectForKey:
let score = results.objectForKey("descriptionOfResult")
//returns the descriptionOfResult value from the results object
setObject:forKey:
results.setObject("The results for a physics exam", forKey: "descriptionOfResult")
//sets the value of descriptionOfResult
To my understanding, #NSManaged magically understands that the variable I've declared automatically uses the above accessors to get and set. I'd like to know how it does that (if what I understand is true), and whatever else it does.
Yes, it kinda really acts like #dynamic -- technically it might be identical even. Semantically there is a slight difference:
#dynamic says 'compiler, don't check if my properties are also implemented. There might be no code you can see but I guarantee it will work at runtime'
#NSManaged now says 'compiler, don't check those properties as I have Core Data to take care of the implementation - it will be there at runtime'
so you could even say: #NSManaged is syntactic sugar that is a more narrow version of dynamic :)
https://github.com/KyoheiG3/DynamicBlurView/issues/2
here someone even used #NSManaged without CD because he wanted the #dynamic behaviour
In the apple docs, for Custom Managed Object Class, they quote properties example like...
To me it seems there is no difference, I have used #dynamic in objective C, it seems #NSManaged is the replacement in Swift.
Above mentioned answers are right. Here is my understanding.
#NSManaged indicates that the variables will get some values when we run the app. Coredata automatically creates getter and setter for such props. It silences the compiler for warnings.
NSmanaged is subclass of NSObject.
#NSManaged means extra code will be given to these props at runtime.
It tracks the changes made to those properties.

Expensive Object management in Swift

I have been looking at Swift the last couple of days and it looks good, I am confused on a point though even after review of the guide Apple published.
I understand that memory management in Swift uses ARC and therefore quite safe, however in situations where I'd like more fine grained control of object creation and destruction I'm slightly confused.
Take these two simple examples:
In ObjC, when you'd (for example) like a UIViewController you intend to push to stay around for the lifetime of your app and only be created once (say because it's expensive to create), you'd make it a property and then wrap it's Alloc Init like this:
if (!self.myProperty)
{
self.myProperty = [[MyObj alloc] init];
}
This way it only creates once, keeps state and the same object instance can be reused indefinitely, yielding known object references, and good performance not having to recreate each time the viewController goes out of scope.
Another example of this is with NSMutableString, vs Swifts String.
You can set an NSMutableString's string many times and it will keep the same object reference, however this doesn't seem to be the case with a Swift String when changing it.
This may just be 'deprecated thinking in Objective C' but is there a best practice with regard to keeping around expensive objects or to keep state (same object) for certain objects during the lifetime of their usage.
I think what you're looking for is a "Lazy stored property":
The example in the swift docs is:
class DataManager {
#lazy var importer = DataImporter()
var data = String[]()
// the DataManager class would provide data management functionality here
}
and it says about #lazy:
A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the #lazy attribute before its declaration.
The comment about NSMutableString is a little different, you can continue to use NSMutableString in your swift code, but Apple are encouraging developers to use the Swift built-in types whenever possible :)
see the "String Mutability" section in the swift docs

Why isn't there a default implementation of NSCoding?

I understand how to use NSCoding to convert my objects to archive objects. That's not my question.
What I'm wondering is why there isn't a default implementation of NSCoding that could handle probably 99% of cases.
For instance, every time I write a custom class that I want to archive, I perform the following:
Implement -(void)encodeWithCoder: and -(id)initWithCoder:.
Go down my property list, writing a pair of statements (one encode, one decode) for each property.
If the property is an object, I use the encode/decodeObject method.
If the property is a value, I use the corresponding encode/decode method.
I always use the property's name as my key.
I would suspect that almost every implementation of NSCoding is exactly like mine, with the only changes being the particular properties that need to be manipulated.
It seems to me that this would be a perfect place for a standard implementation, with the option to override if your particular case if funky.
Do I have a misunderstanding of what's going on? If not, could I add a category on NSObject to implement this common method on all objects in my projects?
I suspect that the answer to your question is simply that NSCoding was designed long before Objective-C properties existed. (NSCoding was part of the OpenStep spec in 1994, whereas properties arrived with Objective-C 2.0 in 2007.) Additionally, some classes have properties that are not appropriate to be serialized for later.
However, your proposed solution could be a great time-saver! At least one such solution already exists. Check out AutoCoding.

Resources