in statement in for loop - objective-c

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.

Related

Best way to Declare & Initialize String Variable in Objective C

I am new to Objective C. we can create String Object by one of these. can anybody tell difference & which is best,simplest way to doing this?
NSString *simpleString = #"This is a simple string";
NSString *anotherString = [NSString stringWithString:#"This is another simple string"];
NSString *oneMorestring = [[NSString alloc] initWithString:#"One more!"];
NSMutableString *mutableOne = [NSMutableString stringWithString:#"Mutable String"];
NSMutableString *anotherMutableOne =[[NSMutableString alloc] initWithString:#"A retained one"];
NSMutableString *thirdMutableOne =[NSMutableString stringWithString:simpleString];
The First method is the simplest and best method for creating string instance if the string is constant. The first method is also prefer as it follow Modern Objectice-C Language.
The Main deference between NSString and NSMutableString is that NSString object is constant. and we can't change or update its value. But NSMutableString has property to change or updates its value.
It really depends on what you want to do.
For simply creating a string from a constant, your first example is best.
stringWithString pretty much just creates a copy of a string, so I don't use it much.
You might want to check out stringWithFormat and stringByAppendingString. Those are two that I use most often.
If you enable ARC, then you don't need to worry about retaining strings. Alloc/init or class factory methods are essentially equivalent under ARC, so use whichever you like best.
There is nothing a best way... It is upto our requirement. However most of the time we opt for manual allocated and initized version of NSString or NSMutableString.
First 3 are Constant String, next three are String which you can manipulate.
Line number 1: is simply a const string.
Line number 2: You are copying a const string you anotherString.
Line number 3: You are manually allocating and initializing it. Its upto you or ARC(compiler) to release it.
Similarly with rest Mutable versions.

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.

If I want to make a new instance of an object in a function whose pointer is passed by reference in it

- (void)createAString:(NSString **)str
{
*str = [NSString stringWithString:#"Hi all!"];
[*str autorelease]; // ???? is this right ?
}
How should I use release or autorelease ? I don't want to release outside of the function of course :)
...
NSString *createStr;
[self createAString:&createStr];
NSLog(#"%#", createStr);
You're correct that you'd generally want to return autoreleased (or the like) objects from out params when you use this form. Your assignment statement in the function that sets *str to a string:
*str = [NSString stringWithString:#"foo"];
is already doing the right thing, because that method returns an instance of NSString that the caller doesn't own. Just like you could return this string object from your function without any further memory management, you can set it as the outparam as you've done. Your second snippet showing the call site is fine.
This said, I'm worried about a few things in your code that you should be sure you understand:
The value of str inside the method is still a **, and sending that a message (as you've done for the speculative autorelease) is nonsense. Be sure you fully understand doubly indirected pointers before using them too liberally. :) If you need to send str a message after creating it, send it to *str, which is what contains the NSString *.
Setting an outparam like this when the function returns void is not idiomatic Cocoa. You would normally just return the NSString * directly. Outparams are rare in Cocoa. (Usually just NSErrors get this treatment from framework calls. Otherwise they conventionally use name like getString to differentiate them from normal get accessors which don't use the word "get".)
I hope -stringWithString was just an example. That method is almost never used in practice, since it's equivalent (in this case) to just using a #"string literal" (although that would muddy your example).
Instead of using a double pointer, would it not be more elegant to use an NSMutableString instead?
- (void)createAString:(NSMutableString *)str
{
[str setString:#"Hi all!"];
}
....
NSMutableString *createStr = [[NSMutableString alloc] init];
[self createAString: createStr];
NSLog(#"%#", createStr);
[createStr release];
Or, even better, just have the createAString method return an NSString.
- (NSString *)createAString
{
return #"Hi all!"; // this is autoreleased automatically
}
I wouldn't want to presume that your needs are this simple, though. =)

confused about NSString *str

I am kind of confused by the behavior of NSString *str..
I assigned it in several ways, sometimes it works, and sometimes it becomes null.
NSString *str = #"/hi/hello"; // this one always works
// this sometimes becomes null after the function ends
NSString *str2 = [str lastPathComponent];
// as above
NSString *str3 = [NSString stringWithString:str2];
NSString *str4 = [NSString initWithString:str3];
I am not quite familiar with the object behavior of Obj-C, is it just like C++?
If so, how can I do assignment safely like
string str = "hi";
string str2 = str;
behaves in C++?
ex: I declare a string in my .h file,
how to assign it safely that it wouldn't become NULL after a function ends?
I know it's a very basic question, but I can't find the answer in NSString reference page.
Really thanks for any help!
The behaviour is not just like C++. Objects are reference-counted. If you want to keep one around, you must place a claim on it.
If you create the object yourself with a method whose name includes the word alloc, new or copy then you have ownership already. This is like a C++ new. (When you have created an object with alloc, you need also to initialise it with some method whose name begins init. But you have to create it first. In C++ both things would be considered parts of the single act of construction.)
Objects you receive from other methods (such as two of the three NSString methods you mention) are only transiently available unless you explicitly claim ownership by calling [object retain]. You only need to do this if you want to keep them around beyond the immediate context. (There isn't really an equivalent to this in C++.)
However you gain ownership, you must relinquish it when you are finished by calling [object release]. This sort of like a C++ delete, except that the object isn't actually destroyed until all ownership claims are released.
Getting to grips with this is really really really important, perhaps the only important thing you need to know to use Objective-C. Read the object ownership documentation carefully and you'll be sorted.
I assume you're not using garbage collection? If this is the case then you need to retain the string.
NSString* str2 = [[str lastPathComponent] retain];
I suggest you do some reading on objective-c memory management.
NSString *str = #"/hi/hello";
This works because it creates a string literal. Answers to this question are worth a read to understand these in Objective-C
What's the difference between a string constant and a string literal?
In all these cases you are creating autoreleased strings. These will be deallocated when you return to the application's runloop.
NSString *str2 = [str lastPathComponent];
NSString *str3 = [NSString stringWithString:str2];
In this last one I assume you meant [[NSString alloc] initWithString:str3]
This creates a string that is retained. But this isn't a good way to create static strings.
You should create static strings in your implementation file like this
static NSString *myConstant = #"constantString"

Change the values within NSArray by dereferencing?

I've come across a problem related to pointers within arrays in objective-c.
What I'm trying to do is take the pointers within an NSArray, pass them to a method, and then assign the returned value back to the original pointer(the pointer which belongs to the array).
Based on what I know from C and C++, by dereferencing the pointers within the array, I should be able to change the values they point to... Here is the code I'm using, but it is not working (the value phone points to never changes based on the NSLog output).
NSArray *phoneNumbers = [phoneEmailDict objectForKey:#"phone"];
for (NSString* phone in phoneNumbers) {
(*phone) = (*[self removeNonNumbers:phone]);
NSLog(#"phone:%#", phone);
}
And here is the method signature I am passing the NSString* to:
- (NSString*) removeNonNumbers: (NSString*) string;
As you can see, I am iterating through each NSString* within phoneNumbers with the variable phone. I pass the phone to removeNonNumbers:, which returns the modified NSString*. I Then dereference the pointer returned from removeNonNumber and assign the value to phone.
As you can tell, I probably do not understand Objective-C objects that well. I'm pretty sure this would work in C++ or C, but I can't see why it doesn't work here! Thanks in advance for your help!
Yeah, that's not going to work. You'll need an NSMutableArray:
NSMutableArray * phoneNumbers = [[phoneEmailDict objectForKey:#"phone"] mutableCopy];
for (NSUInteger i = 0; i < [phoneNumber count]; ++i) {
NSString * phone = [phoneNumbers objectAtIndex:i];
phone = [self removeNonNumbers:phone];
[phoneNumbers replaceObjectAtIndex:i withObject:phone];
}
[phoneEmailDict setObject:phoneNumbers forKey:#"phone"];
[phoneNumbers release];
You can't dereference Objective-C object variables. They are always pointers, but you should treat them as though they're atomic values. You need to mutate the array itself to contain the new objects you're generating.
NSArray is not a C/C++ style array. It's an Objective-C object. You need to use the instance methods of the NSArray class to perform operations on it.
In Objective-C you never "dereference" an object pointer to set its value.
Also, you're using what is called Fast Enumeration, which does not allow mutation.
You can also use enumerateObjectsUsingBlock:.
NSArray *array = [NSArray array];
__block NSMutableArray *mutableCopyArray = [array mutableCopy];
[mutableCopyArray enumerateObjectsUsingBlock:^(id object, NSUInteger idx, BOOL *stop) {
[mutableCopyArray replaceObjectAtIndex:idx withObject:[object modifiedObject]];
}];
Checkout How do I iterate over an NSArray?
While this may work to some degree, I haven't tested it, I'd file this under 'bad idea' and not touch. NSArray, and many other cocoa objects, a fairly complex and can have a variety of implementations under the hood as part of the class cluster design pattern.
So when it comes down to it you really won't know what you're dealing internally. NSArray is actually designed to be immutable so in place editing is even doubly a bad idea.
Objects that are designed to let you mess around with the internals expose those through api methods like NSMutableData's mutableBytes.
You're better off constructing a new NS(Mutable)Array with the processed values.