How to use id variable in objective-c? - iphone

I have an NSArray that contains two types of objects. Lets call them Apple and Orange.
Apple *myApple = [self.searchQueryResults objectAtIndex:indexPath.row];
When I am building my cell's I don't know what type is in my array, apples or oranges. How can I use the generic id type to store the object, and then cast appropriately?

You can use isKindOfClass:(Class)aClass to test the class type:
if ([myObject isKindOfClass:[Apple class]])
// do stuff
I'm not sure why you think you have to cast though. NSArray doesn't care what type of object you store in it, so when you pull it out, it'll still be the same object. But if you want you could still cast by doing something like
Apple *myApple = (Apple *)myObject;
Anyways, knowing the type of class it is should be enough for you to take appropriate action, since it's my understanding that you're showing both types in the same table, all you really need to do is appropriately display their different properties.

Don't mix types of classes in an NSArray.
You can do it, you can run checks for the type - but it's a really bad idea, UNLESS they are both part of the same subclass tree (say, both derivatives of Fruit). Then at least something looking in there can assume what kind of Fruit it might be, and check for particulars.
Basically you will save yourself a lot of headaches if you don't mix types in container classes, when somewhere down the road some bit of code figures for some reason there are only Apples in there but someone throws in a Pear. Then, BOOM!

Related

Objective C convention: When to use For and when to use With

According to the Apple guideline , seems it is confusing, e.g. for method viewWithTag
In Java, I would have a method called
getViewByTag // Java version, equivalent to viewWithTag in Obj-C
But I also found there are some method like objectForKey, so why not just use objectWithKey instead?
getObjectByKey or just get // Java version, equivalent to objectForKey,
// but why not objectWithKey? Or not viewForKey above?
I actually think it is much simpler than what most answers think. I think it has less to do with complex programming language specifics, and has more to do with the uniqueness of the object in question.
When you say viewWithTag:, you are asking the UIView for any view that has that tag. There might be several. The UIView will return one of 'em.
However, objectForKey: (to me) sounds like there should be a single object (or nil) associated with that key. So, the key kinda exists and is bound (tightly coupled) to a single object.
EDIT:
There is an answer mentioning the existence of "by", which further implies how the convention has nothing to do with programming language complexities. It's just natural English.
NSString's stringByAppendingString:, for example, uses by, only because the function is written with a the verb appending. You can't say withAppending, that's bad English.
From my observation
While setting/getting the objects, you use WITH.
e.g. For setting of NSMutableArray object
- (id)initWithCapacity:(NSUInteger)numItems
While setting/getting the properties for objects, you use FOR.
e.g.For setting value for property of type NSMutableDictionary
- (void)setValue:(id)value forKey:(NSString *)key
Hope this helps in clearing your doubt
It seems like with is used for properties that directly belongs to an object. A UIView has a tag property so viewWithTag:14 could be rephrased as "Find the view whose tag property is 14".
When you put an object in a dictionary, associated to a key, this key is not necessarily part of the object itself. objectForKey:#"foo" is a way to say "Look for an object that's linked to the key "foo".
The Apple guidelines do not make any such claims as to when to use for or with. The point of the coding convention is to indicate what the types of the arguments may be and to write method signatures which are natural sounding.
The reason for the for or with in the method name is to identify the type or purpose of the first parameter to the method, which helps it read better.
Apple itself uses several conventions but that is the basic purpose, there is no concrete right or wrong just try to identify the first parameter of the method in the method name with either for or with.
And as for Apple conventions - get(whatever) is not even part of the actual conventions, so you could ask when do I use get or not.
Read this http://cocoadevcentral.com/articles/000082.php
also dont forget (by) NSURL urlByAppendingPathComponent etc - get a feel for it and you wont go wrong
You use "with" whenever the parameter is owned or to be owned, or will be a relatively permanent attribute by the object to the left of the "with" word.
initWithCapacity / arrayWithCapacity - the capacity will be an attribute of the container object being called and will be relatively permanent (until you add objects to it beyond the initial capacity)
viewWithTag – return a view "having" the specified "tag" attribute.
Whereas you use "for" to denote a looser association between the "desired" object and a "token" object that you use to get to it.
- objectForKey / attributeForValue – usually the "object" does not own the key.
- documentForWindow – the window is owned by the window controller and not the document. Furthermore there could be more than one window for each document.
But for looser associations of multiple
objects of the same type within a single method call, it's customary that you use something like:
doSomethingForFoo:withThisOtherFoo:havingYetAnotherFoo:
So the order for such complex call is:
for
with
having

String compare vs Class compare in objective-C

I'm writing an objective-C game and I'm at the stage where i should start optimising some of my code in the game loops.
I have an extensive amount of class compare methods used,
if ([obj isMemberOfClass:[SomeClass class]])
etc.
I heard this sort of checking is quite expensive, because I choose only to have 1 array populated with multiple classes, I need some sort of class check.
I was thinking perhaps that adding a property to NSObject subclassing NSObject to contain a string property, that during initialisation i would make equal to the class name of that particular subclass. Then simply doing a
if ([obj.klass isEqualTo:#"SomeClass"])
Would this be beneficial?
I'm trying to keep as much dynamic coding out of the game loops as possible.
Thanks!
Short answer: no. String comparison is prohibitively more expensive compared to other methods of comparing (or: classifying, categorizing) objects.
Long answer: don't optimize what you haven't analyzed, measured and compared. What you really want to do before you start optimizing is to get a clear picture of how your app behaves and what its performance bottlenecks are. The change you're attempting is unlikely to lead to any noticeable change in performance, so I suggest to first find the real bottlenecks.
In this particular case, sending isEqual to an NSString is 4 times slower than isMemberOfClass if the test fails. And such conditional tests fail most of the time, which is why you should ignore the results of the test succeeding.
The successful string comparison is fast because it's a simple pointer comparison, if two strings are equal it is likely that they point to the same memory address. If they're not equal, then each character in the string will be compared for equality, probably by using the hash method.
Here are the results of the Object Comparison tests that I added to my performance test project. You can use that project to make further tests.
This is not really a direct answer to your question but is an answer in a broader sense.
In Objective-C the philosophy is more like that of Smalltalk in which you send the message and let the object decide what to do with it. If you find yourself having to do lots of tests to see what class an object is, you need to rethink your design.
For instance, if you have an array of objects and you want to convert each one to an integer to do some maths on it, you can do something like this:
for (id anObj in array)
{
int anInt = [anObj intValue];
// do something with anInt
}
It doesn't matter what the class of each anObj is, you can send -intValue to it. If your array is full of NSStrings and NSNumbers, for example, it doesn't matter, the code above will do what you expect.
Many classes do not define a method for the selector -intValue. For example, if you send that message to an instance of NSData it will respond by throwing an exception. There are a couple of ways to resolve this depending on circumstances.
ignore objects that don't respond to the selector by testing to see if the object knows about the selector
for (id anObj in array)
{
if ([anObject respondsToSelector: #selector(intValue)])
{
int anInt = [anObj intValue];
// do something with anInt
}
}
Define the selector for all classes you know will be put in the array. This is done by declaring a category. This way you can extend any Objective-C class without subclassing. For instance, you can define an intValue method for NSData that returns its length, or the sum of its bytes or some other appropriate value.
Formalise the requirement by declaring a protocol. You can then test for conformance to the protocol, or rely on compile time checks to make sure the objects you put in the array conform to the protocol.
There are lots of things you can do, but you need to get away a bit from the C++/Java model of class hierarchies. Objective-C is much more flexible in that respect.

Reflection in Objective-C (iPhone)

I want to populate [MyClass class] from a JSON string.
I use json-framework to get the NSDictionary, and it's dead easy to instantiate and setValue: forKey:... on my data object.
But for more complex data objects with classes as members of MyClass,
ie:
MyOtherClass *classNoTwo
I tried with
Class test = object_getClass(myClass.classNoTwo);
id foo = [[test alloc] init];
But foo is nil/null. The only way I found to get around it is to in my init method of MyClass is to alloc memory for it, and later replace it.
I would also like to know how to get rid of the myClass.classNoTo reference, as I am not supposed to know all the properties in my general parser.
Please don't just tell me to read the documentation, because I've done that, and I can't figure it out.
Thanks in advance
Try calling class_getProperty() to access a property of a particular name and then property_getAttributes() on the property returned by the first function. This will return a string that encodes the property's attributes, including the type. The format of the string is explained in Property Type Strings in the documentation.
Finally, when you have derived the type of the property, use NSClassFromString() to instantiate an object.
Also see the docs for the two functions mentioned for more details.
I have written a very simple dependency injection container called Factory. I do not get your question entirely, but the problems we solve look similar. Take a look at my sources, they are very simple and should get you started. You might be interested especially in the ClassAnalyzer class. It’s just a hack, but you should be able to get what you want from there.

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.

Incompatible pointer type: How can I use a CFType derived object within NSObject derived collection objects?

I'm trying to use ABRecordRef within an NSMutableArray, but it doesn't seem to work. I know that ABRecord is a C class, but I thought that ABRecordRef was the work around Objective-C class that allowed me to use it with NSObjects. What do I need to do to make this work?
What do you mean by "Not Working"? As in, you get compile or run-time errors?
As I noted in the response to the other poster, you can't use the Objective-C API on the iPhone (There also is no true ABrecord class to brdge to).
Generally it's a really good idea with the address book stuff on the iPhone to copy out elements you are interested in, and save the copied values off in something like a dictionary. If you need to save all the elements, you have to have code that reads every value as defined in the AddressBook.h header file, there's no API way to generically walk the records.
Also remember that at any time, the user might change the address book if they quit your app and come back - so be careful about what you change after they relaunch the app if you are storing values!!