Objective C Keyword 'in' - objective-c

Im having some problems understanding some code in a programme I have inherited.
CGPoint tapLocation = [gesture locationInView:self.view];
for (UIView *view in self.view.subviews){
if (!CGRectContainsPoint(view.frame, tapLocation)){
//do something
}
}
The problem is that I have no idea what the keyword 'in' is doing. I've searched around and can only find some obscure reference to it and a post here.
The post says that:
in: argument is an input argument only and won’t be referenced later
I don't really see how this applies to the code above. Any help would be greatly appreciated.

I think apple calls this fast enumeration.
In other languages a similar functionality is provided by a "for each"-loop.

The "in" you're seeing there is part of Fast Enumeration.
Here is some documentation for it.
EDIT: And Derek pointed out another bit of documentation in his comment below.

It's a succinct way to iterate through a collection. Where it says:
for (object in collection)
it means "this code happens once for each object in the collection".

The in in the link you've specified in your question is entirely different from the in in the for loop. The farmer comes under #encoding and the later comes in the context of for loops. This kind of for loop is called for-each loop in general, and in Objective-C it is called fast enumeration.

It creates an enumerator automatically for you such that you can iterator over the collection. So the collection has to conform to NSFastEnumeration.

in is used to iterete through an array.
For instance:
NSArray *values = [NSArray arrayWithObjects:#"val1", #"val2", #"val3", nil];
for (NSString *val in values) {
NSLog(#"Value = '%#'", val);
}

Basically, this is an extension of the for loop built for objective-c.
Think of this code like this:
for (NSArray *arr = UIViewGetSubviews(UIViewControllerGetView(self)), i = 0; i < arr.count; i++) {
}
Note that the actual implementation uses a NSEnumerator, not a for with integer variable loop.

Related

Quick way to tell what objects NSArray contains

I'm currently working with someone else code, so i have a question is there a way to quickly tell what objects i have in NSArray.
In code i have for example:
Someclassobj.arr
And i know there is an array as a property in Someclassobj and of course i can see the definition of it, but still dont know what objects are inside. Could be NSString, NSDictionary,ObjectDefinedByUSer... How to quicly tell?
There is a method to check classes? If i execute:
id someUnknownObj = [Someclassobj.arr objectAtIndex:0];
How to check it? (i know isKindOfClass isMemberOfClass methods, but its doesn't work for me).
Of course there is doesn't have to be code method, could be something like option+click.
Will do the trick:
NSLog(#"%#",yourArray);
If you want to avoid this kind of stuff:
1) Put a breakpoint as soon as the NSArray has the objects.
2) Go to the Console on Xcode and do:
po yourArray
A great article about using the console in Xcode here.
you can do stk like this :
NSArray *arr; // Array with random stuff
for (id elt in arr) {
if ([elf iskindOfClass:[NSString class]])
NSLog(#"Object = NSString);"
}

Enumeration and removing a particular object from NSMutableArray

I'm having trouble removing items from my NSMutableArray. I'm extremely new to Objective-C, so please bear with me.
So far, I have the following: I'm trying to remove a line from the array if it has certain text inside. I cannot do this while fast-enumerating, so I'm trying to store the index, for removal after the enumeration has finished. However, I'm being told that this makes a pointer from an integer without a cast. Confused!
//First remove any previous Offending entry.
//Read hostfile into array.
NSString *hostFileOriginalString = [[NSString alloc] initWithContentsOfFile:#"/etc/hosts"];
NSMutableArray *hostFileOriginalArray = [[hostFileOriginalString componentsSeparatedByString:#"\n"] mutableCopy];
NSInteger hostFileOffendingLocation;
//Use a for each loop to iterate through the array.
for (NSString *lineOfHosts in hostFileOriginalArray) {
if ([lineOfHosts rangeOfString:#"Offending"].location != NSNotFound) {
//Offending entry found, so remove it.
//[hostFileOriginalArray removeObject:lineOfHosts];
hostFileOffendingLocation = [hostFileOriginalArray indexOfObject:lineOfHosts];
//NSLog(#"%#", hostFileOffendingLocation);
}
}
//Release the Array.
[hostFileOriginalArray release];
//Remove offending entry from Array.
[hostFileOriginalArray removeObject:hostFileOffendingLocation];
My real question is why are you releasing your array before modifying it
try moving
[hostFileOriginalArray release];
to after
[hostFileOriginalArray removeObject:hostFileOffendingLocation];
You can do this without the loop by calling [hostFileOriginalArray removeObjectIdenticalTo:#"Offending"];
Note that it will remove multiple instances of the offending object, but that looks like what you want anyway. It will also do the operation in a fast way, without you having to worry about the implementation detail of which loop to use.
As a general rule (especially with the really commonly used objects like containers and NSString), check the class reference to see if Apple already has a way of doing what you want to do. It makes your code more readable to other Cocoa users (including future you), and reduces code maintenance- you're now leaving it up to Apple to add new technologies like Fast Enumeration to their code, and you get it for free when you link against new versions of the SDK.
Also, you should probably return hostFileOriginalArray at the end of the function, so it can do something useful- you can return it as an autoreleased object.
//Remove offending entry from Array.
[hostFileOriginalArray removeObjectAtIndex:hostFileOffendingLocation];
//Release the Array.
[hostFileOriginalArray release];
you should have been getting compiler warnings... take a look at them, they are usually very helpful, I always try to have 0 warnings... that way I know where I have done something careless.

in statement in for loop

i have a for loop state ment as under:
for(NSString* name in nameArray)
nameArray is NSArray.
In the above statement, what does it mean for: NSString* name in nameArray
Iterate through all NSString* in nameArray.
Can be written less cleanly:
for (int i=0;i<[nameArray count];++i) {
NSString *name = [nameArray objectAtIndex:i];
// Do stuff
}
Keep in mind: Don't iterate a mutable array and mutate it (and make sure no other thread does). In such a case you need to call count every iteration like displayed above.
This is fast enumeration syntax introduced in Objective-C 2.0. Check this tutorial for the details. Also you can Google "objective c fast enumeration" for many other resources available online.
It means that the code inside the parenthesis will be executed for every object in the nameArray, which you will access through the NSString *name variable.

Objective-C - How to implement an array of pointers in a method declaration

Ok, if you take a look at my two previous posts (Link #2 in particular), I would like to ask an additional question pertaining to the same code. In a method declaration, I am wanting to define one of the parameters as a pointer to an array of pointers, which point to feat_data. I'm sort of at a loss of where to go and what to do except to put (NSMutableArray*)featDataArray in the declaration like below and access each object via another pointer of feat_data type. BTW, sorry to be asking so many questions. I can't find some of the things like this in the book I am using or maybe I'm looking in the wrong place?
-(void)someName:(NSMutableArray*)featDataArray;
feat_data *featDataPtr = [[feat_data alloc] init];
featDataPtr = [featDataArray objectAtIndex:0];
Link #1
Link #2
Your declaration looks fine. "NSMutableArray*" is an appropriate type for your parameter. (Objective-C doesn't have generics so you can't declare anything about what's inside the array.)
One problem I see in your code is that you allocate an object for no reason and then throw away the pointer (thus leaking memory).
I don't know what it is that you are trying to do, so here are some things that you can do with an NSMutableArray:
- (void)someName:(NSMutableArray *)featDataArray {
feat_data *featDataPtr = [[feat_data alloc] init];
[featDataArray addObject:featDataPtr]; // add an object to the end
[featDataPtr release];
feat_data *featDataPtr2 = [[feat_data alloc] init];
[featDataArray replaceObjectAtIndex:0 withObject:featDataPtr2]; // replace an existing entry
[featDataPtr2 release];
feat_data *featDataPtr3 = [featDataArray objectAtIndex:0]; // get the element at a certain index
// do stuff with featDataPtr3
}

Is there an easy way to iterate over an NSArray backwards?

I've got an NSArray and have to iterate over it in a special case backwards, so that I first look at the last element. It's for performance reasons: If the last one just makes no sense, all previous ones can be ignored. So I'd like to break the loop. But that won't work if I iterate forward from 0 to n. I need to go from n to 0. Maybe there is a method or function I don't know about, so I wouldn't have to re-invent the wheel here.
To add on the other answers, you can use -[NSArray reverseObjectEnumerator] in combination with the fast enumeration feature in Objective-C 2.0 (available in Leopard, iPhone):
for (id someObject in [myArray reverseObjectEnumerator])
{
// print some info
NSLog([someObject description]);
}
Source with some more info: http://cocoawithlove.com/2008/05/fast-enumeration-clarifications.html
Since this is for performace, you have a number of options and would be well advised to try them all to see which works best.
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:…]
-[NSArray reverseObjectEnumerator]
Create a reverse copy of the array and then iterate through that normally
Use a standard C for loop and start and work backwards through the array.
More extreme methods (if performance is super-critical)
Read up on how Cocoa implements fast object enumeration and create your own equivalent in reverse.
Use a C or C++ array.
There may be others. In which case, anyone feel free to add it.
From here:
NSEnumerator* myIterator = [myArray reverseObjectEnumerator];
id anObject;
while( anObject = [myIterator nextObject])
{
/* do something useful with anObject */
}
[NsArray reverseObjectEnumerator]
for (int i = ((int)[array count] - 1); i > -1; i--) {
NSLog(#"element: %#",array[i]);
}