I have a for in loop where I do not quite get the objects I expect to get.
I have a CCLayer class called MainLayer where I add children of class MyUniqueClass. However if I try to get all MyUniqueClass objects, I get other CCNode objects as well. Here's what I do in MainLayer:
for (MyUniqueClass *mUC in self.children){
NSLog(#"%#", mUC); //Here I get all kinds of objects
}
Try to figure out why the CCNode objects are there. Somehow they've been added as children.
Or just ignore that and do this to filter out other node classes:
Class uniqueClass = [MyUniqueClass class];
for (MyUniqueClass *mUC in self.children)
{
if ([mUC isKindOfClass:uniqueClass])
{
NSLog(#"%#", mUC);
}
}
You seem to believe that typing the loop variable as MyUniqueClass * will cause the loop to only cover objects belonging to that class. That isn't how fast enumeration works. It doesn't interact with the type checker at all. Giving a static type to the loop variable just lets the compiler do type checking on the things you do in the loop body (so it can warn you if, say, you're accidentally using a text field like a text view) and lets you access the object's properties with dot syntax. If you want to only operate on objects of a certain class, you'll have to explicitly check in your loop body as shown by LearnCocos2D.
Related
Is it possible to check and get the name of the class an object was initialized in?
Example: I have Class A. I created object ABObject using [[ABOBject alloc] init]; via an instance method.
How can I find out the class from which an instance ABObject was created, namely "A" here?
Objects can be created outside the context of a class, so it wouldn't make sense for this to be a built-in language feature.
If you do have to do this, one way to work around it would be to use the objc_setAssociatedObjects() function in objc/runtime.h immediately after any such object was instantiated. Something like:
ABObject *object = [[ABObject alloc] init];
objc_setAssociatedObject(object, #"InstantiatingClassKey", [self class], OBJC_ASSOCIATION_ASSIGN);
Then you could get it with objc_getAssociatedObject(object, #"InstantiatingClassKey").
I think you'd be better off re-assessing your design because this is not going to be particularly maintainable. Even extracting this into a category on NSObject to remove duplicated code you'll still have an extra step to remember and weird relationships between your objects.
Also, as Martin R. points out in the comments, I'm taking a shortcut and passing a string literal as the key argument for the function, in reality you'd want to follow the practice of using the address of some static or global variable.
I know what a function is, but I am trying to write a few into my project. I have just watched a video series on Objective-C from Lynda.com where I got the idea from.
In the video is it is explained that I can write a function like this:
void declareWebView ()
However if I write it like that into my code, the error comes up and says that my _webView and self (as self.view) are not available.
if I write it like this:
-(void) declareWebView
Then I do not have an issue.
Any ideas on how to get the first one right?
As far as I can tell, I cannot set any parameters with the second way of writing.
The first is as you said called a function. It is part of the C part of Objective-C, and is not connected to objects or classes, so the variable self or any instance variables of an object don't have any meaning. You can pass it variables that are objects though like so:
void my_func(NSString *string, id someObject, int someInt);
void my_func(NSString *string, id someObject, int someInt)
{
NSLog(#"string = %#, someObject = %#, someInt = %d",string,someObject,someInt);
}
The second is a method, and in a method you can access self and, within instance methods, access instance variables. Replacing the "-" in front of the method with a "+" makes it a class method. In a class method you can't access instance variables and self refers to the class itself, not an instance.
Hope this helps!
The first way is written in the language C. The second way is written in Objective-C. Objective-C methods must be declared the second way. You cannot access your object's private members and properties from within a C function directly, but you could use accessor methods on the Objective-C object and call them from a C function.
I am working on an iphone app in objective-c and I am having trouble with making an array out of a class variable, for example...
I have a class named Cube and I am tryin to make an instance of this class named map that is an array
Cube map[10][10];
Xcode then says it is an error and suggests I do this
Cube *map[10][10];
When I do it this way though ^ I cannot access one of my methods I defined in the class Cube, now this is not ALL my methods, it is just one single method that wont work anytime I try to call it. The only thing different about this method than the others is that I pass a parameter to it. The Cube class declaration and definition both compile flawlessly.
Can anyone explain to me how to make a class with a 2 dimensional without turning it into a pointer. Also why does xcode recommend I make it a pointer, and why doesn't the method work when I do it this way?
You probably want to use a Cocoa style array, i.e. NSArray or NSMutableArray instead of C-style array. It is much more flexible and is designed to work with Objective-c objects. Have a look at this simple tutorial on using a Cocoa array: http://iphonelearning.wordpress.com/2011/08/24/nsarray-and-nsmutablearray/.
The standard approach for this in Objective-C is to create an NSArray(or NSMutableArray) of an NSArray (or NSMutableArray). Assuming you want to be able to manipulate the array after you create the array object, your code would look something like this:
NSMutableArray* cubeGrid = [NSMutableArray new]; // Note that this code assumes you are using ARC.
// add row 1
NSMutableArray* cubeRow1 = [NSMutableArray arrayWithObjects:cube1,cube2,cube3,nil]; // you will need to add cube 4 to 10 in the real code
[cubeGrid addObject:cubeRow1];
// add row 2
NSMutableArray* cubeRow2 = [NSMutableArray arrayWithObjects:cube11,cube12,cube13,nil]; // you will need to add cube 14 to 20 in the real code
[cubeGrid addObject:cubeRow2];
// and you will create the rest of the rows and add to the cubeGrid array
To access the elements you would do something like this:
for (id cubeRow in cubeGrid) {
if ([cubeRow isKindOfClass:[NSArray class]]) {
for (id cube in (NSArray*)cubeRow) {
if ([cube isKindOfClass:[Cube class]]) {
// Do things with cube
}
}
}
}
What you might also want to double check is whether the method that you are trying to access is declared in the header file.
You may want to take a look at this this answer.
I have an array filled with instances of a custom class which contains two String properties, firstname and lastname. Both have a getter method which is equal to the name of the property itself. There is also a method for retrieving the Full name of a person called "getFullName". Consider the example below.
CustomClass *person = [[CustomClass alloc] ...];
person.firstname // Returns "Thomas"
person.lastname // Returns "Meier"
[person getFullName] // Returns "Thomas Meier"
Now I would like to sort this Array by Fullname in a descending Order. I have been looking at some array sorting methods but was not quite able to figure out how to go about this. I guess that I have to create some kind of comparison function which compares two elements, yet how do I tell the SDK which values to pass to this method and where should I place it (in the custom class or in the class where the sorting happens?). Maybe there is another/better way of going about this? Admittedly I have close to none experience with sorting arrays.
Thanks a lot for your help!
Ps. The code should run on iOS 3.2
There are a couple ways to do this. One is to put a comparison method on the custom class. Call it -compare: or something like that. That method should take another object of the same custom type as its input. It should return NSOrderedAscending, NSOrderedDescending, or NSOrderedSame, depending on the result of the comparison. (Inside this compare function is where you look at your own fullName versus the passed-in object's fullName.)
Then you can use NSMutableArray's -sortUsingSelector: method, like this:
[myArray sortUsingSelector:#selector(compare:)];
This works on all versions of iOS. There are block comparison methods available in 4.0+.
I have a class that contains multiple user objects and as such has an array of them as an instance variable:
NSMutableArray *users;
The tricky part is setting it. I am deserializing these objects from a server via Objective Resource, and for backend reasons users can only be returned as a long string of UIDs - what I have locally is a separate dictionary of users keyed to UIDs. Given the string uidString of comma separated UIDs I override the default setter and populate the actual user objects:
#dynamic users;
- (void)setUsers:(id)uidString {
users = [NSMutableArray arrayWithArray:
[[User allUsersDictionary] objectsForKeys:[(NSString*)uidString componentsSeparatedByString:#","]]];
}
The problem is this: I now serialize these to database using SQLitePO, which stores these as the array of user objects, not the original string. So when I retrieve it from database the setter mistakenly treats this array of user objects as a string! Where I actually want to adjust the setter's behavior when it gets this object from DB vs. over the network.
I can't just make the getter serialize back into a string without tearing up large code that reference this array of user objects, and I tried to detect in the setter whether I have a string or an array coming in:
if ([uidString respondsToSelector:#selector(addObject)]) {
// Already an array, so don't do anything - just assign users = uidString
but no success... so I'm kind of stuck - any suggestions? Thanks in advance!
The solution you've tried is not exactly wrong, but should look like this:
if ([uidString respondsToSelector:#selector(addObject:)]) {
// Already an array, so don't do anything - just assign users = uidString
Seems that you've forggoten about the ":" - the addObject takes one parameter after all.
However, the proper way to do is to check the class of passed object:
if ([uidString isKindOfClass[NSArray class]])
Hope this was helpful,
Cheers, Pawel
It would be much less confusing - and more in line with the usual Cocoa style - if you let the actual setter take an NSArray or an NSMutableArray:
- (void)setUsers:(NSArray*)usersArray { ... }
... and have another method, say -setUsersFromUidString:, taking an NSString parameter, for the first case:
- (void)setUsersFromUidString:(NSString*)uidString { ... }
Your original approach loses the advantage of self-documentation Objective-C has and will confuse users of the class.