What does #NSManaged do? - ios

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.

Related

Generic Types in NSManagedObject subclass

I'm learning about CoreData and I have a rather basic question.
When I make an NSManagedObject subclass, the generated code in some places goes out of its way to make nicely typed functions for me, but in other cases leaves things annoyingly generic, and I'm confused why.
For example, I have a pair of managed classes with a parent/child, one to many (ordered) relationship. ClassA is the parent which can hold many instances of ClassB.
In the managed code generated for ClassA, it gives the container for the ClassB items as:
#NSManaged public var items: NSOrderedSet?
This is generic, but then later in the code there are lots of conveniently typed functions such as this one:
#objc(insertObject:inItemsAtIndex:)
#NSManaged public func insertIntoItems(_ value: ClassB, at idx: Int)
Great... but a fundamental one is missing: A strongly-typed accessor to get the items collection.
I can easily cast things of course:
var myItem = myObjectOfClassA.items[0] as! ClassB
But I'm confused... Why did they go out of their way to make nicely typed functions in lots of cases, but leave one of the most fundamental things generic?
I'm assuming there is something basic I don't understand here.
Because Swift and Foundation, that's why.
It's as generic as it's currently possible for this kind of relationship. It isn't more generic because
NSOrderedSet is not generic, so you can't have NSOrderedSet<ClassB>, for example.
Although Swift includes generic collections like Array and Set, there is no Swift-y generic OrderedSet collection.
There are also Swift-related gaps in the Core Data code generation. For example if this relationship wasn't ordered, the generated code would still use a non-generic NSSet. There's no good reason for that, but at least it can be cast to a Set.

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.

Swift: why does inheriting from NSManagedObject ruin my properties?

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.

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.

Do I need ARC keywords for properties that I don't synthesize?

I have a property that I do not synthesize, instead I create a getter and setter myself. Therefore, the ARC keywords (strong or weak) have no meaning, I assume, so I eliminate them. This works fine on Xcode 4.3, but when my coworker opens them on XCode 4.2 the compiler complains that there is no strong/weak keyword, so I instructed him to meaninglessly enter the keyword back in again. Which is correct (with or without keywords)?
To be clear: I have a property like this #property (nonatomic) NSString *foo and in the .m file I implement -(NSString *)foo and -(void)setFoo:(NSString *)foo and do NOT include #synthesize foo. Another relevant detail is that there is no corresponding iVar, instead the properties interact with a Core Data object. This will not compile in XCode 4.2 unless I add strong or weak to the keywords.
EDIT I thought of one more relevant thing, one of these properties is on a Protocol, I don't know if that makes a difference.
The declared attributes that you are referencing are optional. To quote the documentation:
Property Declaration and Implementation
The #property directive declares a property. An optional parenthesized
set of attributes provides additional details about the storage
semantics and other behaviors of the property - see “Property Declaration Attributes” for possible values.
Property Declaration Attributes
You can decorate a property with
attributes by using the form #property(attribute [, attribute2, ...]).
Like methods, properties are scoped to their enclosing interface
declaration. For property declarations that use a comma-delimited list
of variable names, the property attributes apply to all of the named
properties.
If you use the #synthesize directive to tell the compiler to create
the accessor methods (see “Property Implementation Directives”), the
code it generates matches the specification given by the keywords. If
you implement the accessor methods yourself, you should ensure that it
matches the specification (for example, if you specify copy you must
make sure that you do copy the input value in the setter method).
If you then use #dynamic instead of #synthesize it is telling the compiler that you will be writing your own methods and prevents it from complaining when it doesn't find suitable methods.
More information can be found here.
borrrden,
First, why do you care to elide your memory policy in your property statement? It announces to consumers of your class what the policy is. Don't you want them to know?
Second, the #synthesize is not a nop. It is the mechanism by which the language support KVO. While you may not be using that now, why would you preclude this use for the future.
Frankly, by not using a full description in #property nor using #synthesize, you are, IMO, engaging in premature optimization. Your current design doesn't save you message dispatches and forces you to manage, if necessary, the creation and typing of ivars. And you are losing features of the language.
Unless you have a good reason to get outside the bounds of the preferred Obj-C v2+ patterns, and you haven't listed those, then I would return to using the standard pattern. Then your problem just goes away.
Andrew

Resources