Error using scalar in managed object - ios

I have some code in an app that creates a CoreData managed object. In this code, I use the following line to set a property:
theAuthor.authorID = 1;
The property is declared like this in the managed object header:
#property (nonatomic) uint32_t authorID;
In iOS 5 it works fine, but when I debug in iOS 4.3, I get this error:
Property 'authorID' is a scalar type on class 'Author'. Cannot generate a setter method for it.
Why am I getting this error in 4.3, but not in 5? Should I be avoiding scalar properties? I came to Obj-C from C, so I prefer to work with scalars when I can, as it feels more optimised.
Would I be better implementing the getters and setters or changing my code to use NSInteger or NSNumber instead?

See here for information on using scalar attributes in core data. (By the way, NSInteger is a scalar). Listing 3 is the particular one you are interested in. Basically, you need to write your own accessor for it, but it's not difficult.
As of iOS5, you can use scalar properties in core data. This can be achieved by ticking the appropriate box when generating your managed object subclasses from the data model.

Related

Upcasting NSObject to RLMObject

How would you upcast an NSObject to a RLMObject?
Say you have a model object that's of type NSObject, and say you wanted to dynamically upcast it to RLMObject, how would you do it?
It's worth mentioning that RLMObject's properties can't be populated at runtime, else I probably would've done it through <objc/runtime.h>. (I mean.. They technically can... It would just be too much of a hack)
What I'm trying to do:
The main purpose behind this is to create a caching framework that would dynamically choose between interchangeable caching dependencies such as Realm, SQLite, Core Data, etc. For example, I imagine having a preprocessor flag to hopefully switch from using Realm to SQLite, without having to change my models subclass.
This would require all of my models being a subclass of NSObject, simply because RLMObject wouldn't make sense in a SQLite environment for example.
I've been thinking about this a whole lot, and here's my approach:
1) Loop through the NSObject's properties at runtime & create a key/value object of them
2) Create a subclass of RLMObject at runtime and copy the property list from the passed NSObject model
3) Utilize Realm's initWithValue: to populate the properties
What's your opinion?
It looks like this method that you mention - RLMObject.initWithValue or a static equivalent createInDefaultRealmWithValue has to be called on an RLMObject subclass, or else it throws an exception: "Object type 'RLMObject' is not managed by the Realm".
You need a dynamic schema creation API (what underlies RLMObject), that I don't see being a public API.
An alternative would be to manually encode the object to some dictionary or NSData and attach it to a fixed RLMObject subclass.
You might lose some Realm features by not inheriting RLMObject like knowing when the object becomes dirty, but still probably get some success.
I think you'll get the same problem with Core Data. Normally Core Data supports only NSManagedObject subclasses, and moreover it requires you to define a fixed schema in advance in a model file (represented in code by NSManagedObjectModel).
Of course you could just treat your objects as dictionaries of property names and values, and place them into a giant ("type","id","property","value") table, but it is not the best approach (likely to be slow).
The same strategy is possible to implement with the SQLite backend. Interesting to see which schema would you choose for this.
I'd recommend to look at key-value stores as the backend for this, and avoid SQL. Or treat SQL as a key-value store, as in ("type+id", "encoded_object_data") :)

Why is my property absent from the Realm object?

I'm using Realm for persistence and I cannot access properties which are marked as readonly.
More accurately, I can print them using dot notation, but po object only shows the readwrite properties, and trying to access readonly properties using objectsWhere crashes.
I've tested using a standard NSObject class and the issue disappears (for po obviously), which makes me wonder why/if Realm ignores readonly properties?
That's correct! If a property is marked as readonly, Realm ignores it and doesn't create a backing for it in the database file. This is the same implicit behavior as placing a method in the ignoredProperties method of RLMObject. They are left as traditional Objective-C properties. :)
If you need to make the property visible in the po object command, you can override the - (NSString *)description method of your object and ensure that your object is included in the description string that is printed.
Since readonly properties aren't backed by Realm, they'll be quite limited in what you can do with objectsWhere, as that uses a custom Realm query engine. You can probably check if other Realm properties match that property, but you couldn't create a query using the property itself as the item being searched for.

iOS call properties

I'm a beginner in iOS development and I'm currently watching couple courses online which explain the whole in the backscene getting and setting process.
Somebody thought me that when I'm initializing a variable I should use:
[self setX:1];
And in the rest of the code to acces this variabel I should use:
_x
instead of :
[self x]
The reason for this had something to do with reference counting, but now in the course the person tells me to never use the underscore for anything but in the automatic generated getter and setter?
I know about the dot notation. But concrete question is: "Can I call variabel with the getter and setter without the fear of memory leaks (I'm using ARC) instead of the underscore.
The underlying instance variable for that property is in fact _x. That is how auto synthesised properties work.
However you should consider using the accessors to set the property (using self.x = instead). See this link for more info on Reason to use ivars vs properties in objective c
Your ios version is ios6 that's why it will be direclty get _x.
When you define any property
#Property int x;
ios6 automaticall synthsize using _x; so dont worry you can used _x.

Key-value observation: Can I observe for changes on ALL properties?

Whenever a property on my object is changed or updated I want to change a variable (nonce variable). This nonce is time-based. So everytime a property is updated this nonce gets updated to the current time.
Is there any way to automatically listen for all key changes on my object? Or will I have to manually maintain all keyvalue observers for each property separately?
Many thanks
Did you take a look at the Obj-C runtime functions? See here in the docs. For example, this gives you a list of all the properties in a class Lender. (BTW: I'm not at my Mac, so this is just straight out of the docs):
#interface Lender : NSObject {
float alone;
}
#property float alone;
#end
you can get the list of properties using:
id LenderClass = objc_getClass("Lender");
unsigned int outCount;
objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
you can then get the name of a property:
const char *property_getName(objc_property_t property)
If you pipe those names back into addObserver:forKeyPath:options:context you should be golden.
Some ideas:
1) you can ask the runtime for the properties and ivars, and their types, and use that information to create and take down observers. Obviously a lot of work if you are doing this for one object.
2) if your properties are "regular", meaning all strong objects, then you can use #dynamic (to prevent setter/getter creation), then use resolveInstanceMethod: or other funky methods from NSObject to catch setMyObject: and myObject calls. You could in essence do what the system does for 'set...' calls, and dynamically get the string of the variable. You could then update/get an ivar, maybe one that has a prefix of "-" or something, and you'd be able to do what your observers would be doing.
3) You could put all the ivars in a "Helper" class, and direct all the setters to it (which could of course message you back), using forwardingTargetForSelector:. I'm using this technique (sort of) in one of my github projects

How to use type-safe struct type Core Data attributes with mogenerator?

For attributes of struct types that NSKeyValueCoding can handle, I use the Core Data accessor pattern described in Apple's docs here.
For example, an NSRange struct can be specified in the Core Data model as of type Transformable, then the NSValue rigmarole can be avoided for clients by providing accessors in an NSManagedObject subclass of the form:
Interface:
#property(assign, nonatomic) NSRange range;
Implementation;
- (NSRange) range {
[self willAccessValueForKey:#"range"];
NSRange retVal = range;
[self didAccessValueForKey:#"range"];
return retVal;
}
- (void)setRange:(NSRange)aRange {
[self willChangeValueForKey:#"range"];
range = aRange;
[self didChangeValueForKey:#"range"];
}
Mogenerator's generated NSManagedObject subclasses, however, declare Transformable attributes as NSObject properties, so clients need to get/set NSValues.
What's the best way to handle this situation with mogenerator, whilst (1) keeping with the simple Transformable pattern rather than messing with transient backing attributes, and (2) avoiding any edits of Mogenerator's 'machine' classes?
The ultimate way to deal with this would be, as scc suggested in the previously accepted answer, to change the mogenerator template files. They would need to (a) change the transformable attribute's accessor to be of the appropriate type (NSRange in this instance) and then (b) add the accessors with the appropriate KVO method calls.
As that's more than I have time right now to figure out how to do, my temporary expedient is as follows:
add an attributeValueClassName key to the attribute's userInfo dict (in the Core Data editor), with the value NSValue (just to make sure the generator's accessors will be NSValue rather than NSObject).
in the human-editable mogenerator output, add accessors like those in the question, except with a new name (eg. rangeValue and setRangeValue). The underlying values will still be the persisted NSValues, but my accessors take care of the KVO and boxing/unboxing.
Not ideal, but I do get strongly-typed accessors without having to edit the mogenerator machine files.
Just change the type from NSObject to whatever type you need after the model object generator has finished its job. You should not have any compiler warnings after that.
BTW, when I run the managed object model generator after defining a transformable attribute I do not get NSObject but id. No warnings.
Can you alter the template files that mogenerator uses? (I think) that provided you stay away from scalar values, you can safely use NSObject * instead of id.
For those willing to edit the machine template file, use the following conditional to special case for the transformable NSRange attribute.
<$if Attribute.hasTransformableAttributeType && Attribute.objectAttributeClassName == "NSRange" $>
Here's how I changed my machine template header file. https://gist.github.com/2414047
You are reading the wrong part of the documentation. Please look here:
NSRange doesn't need to be transformed. There are methods for all those basic structures, such as:
NSRangeFromString();
NSStringFromRange();
So you would define the shadow property as something like "rangeAsString" of type NSString.
In your MO subclass you would follow in the docs on how to properly convert and store the value so that core data knows your object became dirty when doing like:
myObject.range = NSMakeRange(0,5);

Resources