CoreData Object typing won't work - iphone

Can someone explain to me why this doesn't work:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = classObject.stringProperty;
But this does:
CoreDataClass *classObject = (CoreDataClass *)[some method that returns a dictionary with exact KVC pairs that match CoreDataClass];
NSString *myString = [classObject valueForKey:#"stringProperty"];
EDIT:
What's the easiest way to cast the dictionary as my NSManagedObjectClass CoreDataClass so I can access properties directly?

It doesn't work since KVC compliance is not at all what defines classes or makes them castable - the class hierarchy exists for a reason, and just ensuring adherence to certain methods doesn't magically make something an instance of a completely different class. Keep in mind that the dot-accessor syntax is just sugar for a method send, so these two are equivalent:
classObject.stringProperty
[classObject stringProperty]
...and the latter obviously isn't valid for instances of NSDictionary (i.e. [[NSDictionary class] instancesRespondToSelector:#selector(stringProperty)] is NO).
Your latter example works because of the very premise of your question: if something is KVC-compliant for the key stringProperty, and you ask it for a value for that key, then obviously you get something back. Furthermore, both NSDictionary and CoreDataClass respond to the selector -valueForKey:, so the message send actually works at runtime.
The best way to get the two across isn't a "cast" at all - it's a complete conversion, at the property level, of the data involved. You might consider creating a custom -initWith... method on CoreDataClass that lets you instantiate its properties from a dictionary, or finding a way to get your method to return an actual instance of CoreDataClass instead of an NSDictionary.
Note that this solution may differ from the "easiest" way to get the data across, which is effectively to keep doing what you're doing and use -valueForKey: (though preferably without the cast, which is misleading).

Casting objects only appears to work (in the sense that you won't get type-checking errors) because it's a hint to the compiler, but it doesn't actually change anything about what the pointer points to, so you are still pointing to an NSDictionary. This is because, at the end of the day, you are essentially casting a pointer to a pointer, but telling Xcode that you are allowed to send a different set of selectors to it.
For NSManagedObjects, creation from a dictionary depends on a few things, but the recommended way is to make a class method on your custom class which will use NSEntityDescription and you NSManagedObjectContext, and sets the properties from the dictionary to the object:
+(CoreDataClass *) coreDataObjectWithDictionary:(NSDictionary *) spec {
CoreDataClass *myInstance = [NSEntityDescription insertNewObjectForEntityForName: #"CoreDataClass" inManagedObjectContext: [myMOCProvider sharedMOC];
myInstance.someProp = [spec valueForKey:#"someProp"];
}

Related

Woes in trapping valueForKeyPath: without a valid path

I have a nested NSMutableDictionary and am successfully pulling out a value at some 'depth' nested in other dictionaries, like:
NSNumber *num = [myDictionary valueForKeyPath:#"league.team.away.score"];
All is good. And I can confirm that all dictionaries at all levels are mutable.
But... what if that key path does not exist?
As expected, I get an NSUndefinedKeyException. I tried a fix with a try/catch tactic, to no avail.
Apple's solution to this concerns overriding valueForUndefinedKey:
"Subclasses can override this method to return an alternate value for undefined keys. The default implementation raises an NSUndefinedKeyException."
Great... so I create a subclass NSMutableDictionaryMod, then I get a complaint...
[NSMutableDictionary initWithCapacity:] method only defined for abstract class. Define -[NSMutableDictionaryMod initWithCapacity:]!
I go define said initializer (and can confirm it gets there in Xcode), but boom it crashes on the self = [super initWithCapacity:numItems]; line.
Then I noticed this Apple gem on NSMutableDictionary:
There should typically be little need to subclass NSMutableDictionary. If you do need to customize behavior, it is often better to consider composition rather than subclassing.
Any suggestions would be appreciated.

Assigning, mutable to immutable array?

Would someone be so kind as to confirm that I am understanding this correctly. My initial response to this was that the mutableArray when assigned to an immutableArray would become an immutableArray, however this is not the case.
Is this because the initial array is allocated as a mutableArray and the immutableArray is just assigned to point to the same object. The compiler gives a warning, but the the code executes just fine at runtime.
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"Teddy", #"Dog", nil];
NSArray *iArray = mArray;
[iArray addObject:#"Snoss"]; // Normally this would crash NSArray
much appreciated
gary.
Don't confuse the physical object that you just created, with how you are effectivley casting it in your code.
In this case, you did physically create a NSMutableArray.
Then you effectivley cast it to an NSArray - which is totally valid - for example, there are many cases where a function might want an NSArray, and you can pass it an NSArray, or anything derived from it (like an NSMutableArray).
The problem is that you get a compiler warning because you are trying to call addObject on an object which the compiler thinks is just an NSArray because that's what it's physical type is.
This will actually work, because it actually is an NSMutableArray, and in runtime would respond to that selector.
It's bad coding practice to do it this way, because NSArray doesn't actualy respond to the addObject selector. For example, I could create a function, like:
-(void) addIt:(NSArray)myThing {
[myThing addObject:#"New String"];
}
The compiler would give you a warning saying the "NSArray" doesn't respond to the "addObject" selector. If you cast an NSMutableArray, and passed it to this function, it myThing, it would actually work.
It's bad practice though, because if you actually passed an NSArray it would crash.
Summary: Don't confuse what the object really is vs. what you are making the compiler interpret it as.
Yes, you are right. You should do
NSArray *array = [NSArray arrayWithArray:mutableArray];
to ensure that nobody can change the array
Your iArray is actually referencing to NSMutableArray instance, that's why it is a NSMutableArray.
Obj-c doesn't have strict check on class types, all objects are of type 'id'.
You could write
NSNumber *iArray = mArray
Compiler will show a warning of wrong cast (not error). But it will work.
Don't mess with pointers, there is no object type transformations as you can expect in C++. (there are overloadable operators for casting object to another class).
Obj-c works with objects much like script/interpreted languages. Dynamic typing (objects only), reflection, dynamic change of methods of instance of classes etc - full flexibility. A perfect mix of speed of low-level C/C++ and flexibility of dynamism.
AFAIK, you are correct. NSMutableArray is a subclass of NSArray, so you can assign mArray to iArray here without a problem.
However, it isn't clean code and you should avoid it.

Should I verify objects inside Foundation API containers?

In languages like C++ and C# when you create a contain such as a std::vector or a C# list you explicitly declare the container type when you create it:
C++:
std::vector<MyObject>
C#:
List<MyObject> list = new List<MyObject>();
Looking at the code above, I know immediately that these containers can only contain objects of type MyObject and the compiler will complain if I try to add an object that isn't off this type.
Since Objective-C is a dynamic language, we don't have the privilege of the compiler warning us about this (because it is a perfectly valid but potentially dangerous thing to do):
Objective-C:
NSDictionary *dict = [[NSDictionary alloc]init];
[dict setValue:[[SomeClass alloc]init] forKey:#"someClass"];
[dict setValue:[[NSMutableString alloc]init] forKey:#"mutableString"];
BOOL classIsSomeClass = [[dict objectForKey:#"someClass"] isKindOfClass:[SomeClass class]];
Instead something like an NSDictionary or NSArray will store and accept objects of any type that inherits from NSObject. I find this in itself very flexible but I cannot really be sure of the object type in the container I can only really know at runtime whereas with c++ or c# I know this at compile time and just by looking at the code.
Should I be validating the contents of the containers when adding, using and removing objects for container classes (NSArray, NSSet, NSDictionary, etc) from Apple's Foundation Framework? Or is this okay in all circumstances and will verification hurt performance much?:
NSDictionary *dict = [[NSDictionary alloc]init];
[dict objectForKey:#"someKey"]; // return nil?
Objective-C's dynamic messaging is much more like dynamic languages such as Python or Ruby. In these languages, the standard paradigm is often known as "duck typing". In other words, if an object instance quacks like a duck (i.e. responds to the message you're sending), it's a duck. In Objective-C, methods can be added at run time by a number of mechanisms, outside of the object inheritance hierarchy. So, it's much more common to ask whether an instance responds to a particular selector:
if([obj respondsToSelector:#selector(myMethod)]) {
[obj myMethod];
}
than to ask whether obj belongs to a certain class' hierarchy.
For the most part, Objective-C developers don't do this check unless they're getting object instances from "unknown" modules. Instead, we rely heavily on compiler warnings (the Objective-C compiler will warn about sending a message to a type that it isn't sure can receive that message) and unit testing. In this case, unit test to confirm that the correct objects are going into the collection and that you get the expected types out of the collection would probably go a long way to allaying your fears.
It does seem to be the "Objective-C Way" to avoid checking the types of an object taken from a collection. It's of course debatable whether this is good, but I think it's part of a general theme of preferring to think about the messages an object responds to rather than the object itself.
An example of this is the various ...Value (e.g. stringValue, intValue, etc.) messages that many objects respond to. Also worth noting is the fact that the id type automatically suppresses any warnings of the so-and-so may not respond to the such-and-such message variety.
I would say the pattern in Objective-C is to only store objects of one type in a container - and pretty much always you are sure of what is going into a container. That's why very few people in practice actually take the time to check the contents of a collection. When I do want to verify something, I usually use isKindOfClass: and a properly typed object to hold an item from the collection.
If you are really concerned about typing for some reason it would be pretty easy to create a wrapper class that implemented typed versions of objectAtIndex: and other common NSArray methods - note I'm not talking about a subclass of NSArray or any other collection, just an object that had similar message names. That kind of thing can be a drop in for lots of uses and you could always add a fall through method to get to the backing collection. But I think it's more trouble than it is worth and moves away from gully embracing the language.
In practice over many, many applications I almost never see "wrong type of object in an array" come up as an issue.
Now for a method that accepts an argument of typeID, that I am a lot more likely to check the type of before use - because those methods tend to take in a much wider range of objects.

Add method selector into a dictionary

I want to add a selector into a dictionary (the main purpose is for identifying the callback method and delegate after finish doing something)
But I find that I can not do that, the program will get an error "EXC_BAD_ACCESS".
Are there any other way for me to add that method selector to a dictionary?
Thanks for your help.
I know this question was answered a long time ago, but just in case anyone stumbles upon it like I did...
The combination of NSStringFromSelector and NSSelectorFromString as answered above is probably the best way to go. But if you really want to, you can use a selector as a value or key in an NSDictionary.
A selector (type SEL) is implemented as a pointer to a struct in Apple's Objective-C runtimes. A pointer cannot be used directly in a dictionary, but a pointer can be wrapped in an NSValue object that can be used.
Using this method you can store a selector as a value in a dictionary using code like this:
dictionary =
[NSDictionary dictionaryWithObject:[NSValue valueWithPointer:selector]
forKey:key];
A selector can be retrieved using code like this:
SEL selector = [[dictionary objectForKey:key] pointerValue];
Similarly for using a selector as a key:
dictionary =
[NSDictionary dictionaryWithObject:value
forKey:[NSValue valueWithPointer:selector]];
value = [dictionary objectForKey:[NSValue valueWithPointer:selector]];
Adding a new entry to a dictionary does two things (in addition to adding it to the dictionary, obviously):
It takes a copy of the key value. This means that the the key object must implement the NSCopying protocol
retains the value. This means that it needs to implement the NSObject protocol
It's probably the second that's causing your EXC_BAD_ACCESS.
There are at least two ways around this.
Firstly, rather than adding the selector you could add the instance of the class that implements the selector to your dictionary. Usually your class will inherit from NSObject and it will work fine. Note that it will retain the class though, maybe not what you want.
Secondly, you can convert a selector to a string (and back again) using NSSelectorFromString and NSStringFromSelector (docs are here).
I get my answer based on the comment of Zydeco:
You can convert between SEL and
NSString using NSSelectorFromString
and NSStringFromSelector
The common idiom in Obj-C is to have specific names for callbacks for specific events. (Such parserDidBeginDocument: from NSXMLParserDelegate). If you really need to be able to specify the names, it is likely that your only recourse is to add the names of the selectors as #"mySelector:withArgument:context:" or somesuch.

How do I generically use KVC to update fields?

Say I have the following Objective-C class:
#interface Foo {
int someNumber;
NSString *someString;
}
and for reasons I won't get into here, I want to use KVC to update, in a generic fashion, the values for those variables:
[f setValue:object forKey:#"someNumber"];
or
[f setValue:object forKey:#"someString"];`
If object is a string and I'm updating the someNumber variable, it seems that I need to know to use an NSNumberFormatter to get an NSNumber and then Cocoa automatically converts that to an int inside setValue:forKey:.
Is there any way to avoid this custom code and have Cocoa infer the conversion to an int from a string, or do I need to catch this situation each time and handle it myself?
The following code should handle the conversion automatically, as long as the object parameter is a member of a class that implements integerValue.
Note that both NSNumber and NSString implement this method.
- (void)setValue:(id)object forKey:(NSString *)key
{
if ([key isEqual:#"someNumber"])
{
someNumber = [object integerValue];
}
//...
}
edit: (side note):
You can avoid writing the method yourself by using objective-c properties. The default implementation of setValue:forKey: will do the work for you, as long as you create properties for someNumber and someString.
You should do the conversion yourself with a number formatter, it gives you finer control than anything that the framework might consider to be appropriate. It is also, probably, not a good idea to use a single instance of an object to update the values for your ivars. More appropriately, you could perform your update based on the class of the object (providing you are not storing in an id by querying the runtime as to the class of the object by means of object_getClassName. More information is available in the Objective-C 2.0 Runtime Reference. But in general, you will likely find bugs in your code as a result of doing things that way.
I'm with wisequark on this one. I think of setValue:forKey: as equivalent to calling the setter directly. If you had a method:
- (void)setSomeValue:(NSInteger)aValue
You wouldn't expect to be able to pass in an NSString and hope the method can figure it out.
Put another way, a key value gives you access to a property, and that property has a type. When using KVC, numbers just get wrapped in an NSNumber object so that there's only one setValue:forKey: method. Therefore, I say it's always the calling code's responsibility to package up the string in an NSNumber object.
It's times like these I lament that Cocoa Touch doesn't support bindings. Bindings would allow you to add a value transformer that could handle the transformation from string to number automatically for you. Maybe in the next version!