Objective-c pointers and NSString - iphone

If I have this code, why doesn't the textview's text update? As far as I knew a * meant a pointer, and I haven't done a copy.
NSString *searchText = myTextView.text;
searchText = [searchText stringByReplacingOccurrencesOfString:#" " withString:#";"];
So why isn't myTextView's text changed as if I did:
myTextView.text = [searchText stringByReplacingOccurrencesOfString:#" " withString:#";"];
And how would I write the code, so that the first code example works as I intend?

The method stringByReplacing... Doesn't change the string, it returns a new string object (autoreleased, according to the naming conventions). So after the 2nd line of code, searchText points to a totally differen NSString object.
Besides, NSString objects cannot be changed, for that there's NSMutableString

If you expect to modify myTextView.text, you have to write it like your second example, and assign a new value to the property you're trying to modify. Assigning a new value to some other variable or property won't do the job - "spooky action at a distance" may work when we eventually have quantum computing, but we're not there yet. :-)
To expand a bit: Yes, searchText is a pointer. But so is myTextView.text, and when you do "searchText = myTextView.text", you're not creating any sort of lasting relationship between the two - all you're doing is making searchText point to the same target as myTextView.text. Changing either one of them after that point will have no effect on the other. So, when you assign the result of stringByReplacing... to searchText, you're making it and only it point to a different target.

Your second example invokes the setter of the "text" property.
Your first example takes the pointer of the string, and then changes the pointer within the same scope. Hence, "text" is not changed.
BTW: Depending on how your property is defined, the setter you use will either copy, retain or assign the value you give the setter. So if you use the following:
#property(copy) NSString* text;
Then yes, the setter will copy the value you give it when you invoke:
myTextArea.text = //some string

Related

Accessing value from array of objects

I am having two arrays, Namely
NMutableArray* first;
NMutableArray* second;
Now I am copying first object to the second array like
for (int i=0;i<first.count; i++)
{
[second addObject:[first objectAtIndex:i];
}
This is ok. I don't know how to access the value of the First Array. I tried like this ,
[second addObject:[[first objectAtIndex:i]name]];
I want to get the name value which is in the first object of first array. I tried using the above line, it is showing some warning. Please help me
Assuming you started with an array like this:
NSArray *array1 = #[#{#name : #"Fred"},
#{#name : #"Bill"}];
You could create a second array that contains the value of a given property of each element of the first array as follows:
NSArray *array2 = [array1 valueForKey:#"name"];
If you then logged the second array...
NSLog(#"%#", array2);
...the resulting output would be
2012-04-18 16:26:11.226 ExampleRunner[23320:707] (
Fred,
Bill
)
EDIT
Note that this will work regardless of whether the objects in the first array are instances of NSDictionary as shown in the example above, or instances of a class or classes that have a name property or instance variable (or an _name instance variable, for that matter). For more information on how and why this works, see the documentation for the NSKeyValueCoding informal protocol:
http://developer.apple.com/library/ios/#DOCUMENTATION/Cocoa/Reference/Foundation/Protocols/NSKeyValueCoding_Protocol/Reference/Reference.html
The brackets are currently in the wrong place:
[second addObject:[[first objectAtIndex:i] name]];
Updated Answer:
Again, I think you should split stuff out into easy to parse lines of code:
for (id theObject in first)
{
// without an actual type, I still think the compiler might
// throw a warning on this next line of code;
// but maybe RJR III is correct and it won't warn.
// I didn't check.
NSString * nameOfObject = [theObject name];
if(nameOfObject)
{
[second addObject:nameOfObject];
}
}
Notice that I do some error checking in here as well (i.e. making sure the name is not nil).
Original Answer:
You're getting a warning because the compiler doesn't know what kind of custom object is being fetched from your call to "[first objectAtIndex: i]". In other words, it doesn't know what kind of object you're trying to get the "name" of.
Cast it to the right type and you'll get rid of the warning.
Or even better, split that one line of multiple things happening at once into two or three lines of code and make your code more readable in the process.

Change the content of a string within an array of strings

This is my code:
NSString *newString = #"new value";
[breakdownCollection objectAtIndex:i] = newString;
breakdownCollection is an NSArray of multiple strings. I need to access a given string contained in the array via index number, and change the string's content to that of the new string. Note that I cannot simply replace the string with the new one, I am only trying to replace its contents.
When I try to do this, however, I get an "lvalue required as left operand of assignment" error.
Any help with this issue would be very much appreciated!
The error you get is because you wrote the assignement instruction incorrectly. That is, you cannot assign newString to [breakdownCollection objectAtIndex:i].
Also, you won't be able to do it this way. Instead, in order to modify string object content, use NSMutableString, which provides methods to do so (NSString are immutable objects).
So, for example you should try :
[[breakdownCollection objectAtIndex:i] setString:newString];
assuming you put NSMutableString into breakdownCollection.
PS : in order to change the object at the index i, you have to use NSMutableArray instead of NSArray, and then call :
[breakdownCollection replaceObjectAtIndex:i withObject:newString];
Good luck !
NSMutableString class reference
NSMutableArray class reference
Use an NSMutableArray instead and then you can use the method -replaceObjectAtIndex: withObject:

iphone [removeObjectIdenticalTo:] doesnt work

I have the following code that populates an array (this is within a loop):
NSString *code = [NSString stringWithFormat:#"%# - (%#) %#",[tempDic objectForKey:#"state"],[tempDic objectForKey:#"city"],[tempDic objectForKey:#"name"]];
[tempArrayOfAirports removeObjectIdenticalTo:code]; // checks for a previous object, then removes if found
[tempArrayOfAirports addObject:code]; //adds the object
Previously, code had simply been:
NSString *code = [tempDic objectForKey:#"city"];
[tempArrayOfAirports removeObjectIdenticalTo:code];
[tempArrayOfAirports addObject:code];
Which worked fine, but for some reason, changing "code" is keeping it from finding other identical strings. My result is a huge array with many, many repeated objects.
Since you're creating a new string in your new code, you probably want to use removeObject: instead of removeObjectIdenticalTo:. The removeObjectIdenticalTo: method uses object addresses to test for "identicalness," whereas removeObject: tests for equality using isEqual:. If you only care about the contents of the strings, use removeObject:.
In your old code, you probably inserted the same object into both tempDic and tempArrayOfAirports so the address check worked. This is not the case in your new code, in which you create a new string (at a new address) with stringWithFormat:.

Set Multiple Variables to Same Value

I have dozens of NSStrimgs that when the app loads I want to all be set to the same set. All of them. How can I do this without typing out every single one? Is there a shortcut method?
Thanks.
Also the problem is that Josh isn't specific enough about how he's using his dozens of strings... I think this would be better:
NSMutableArray *stringsArray = [NSMutableArray arrayWithCapacity:1];
NSString *tempStr = #"My unique string"; // Thanks Sven!
// Say you want a dozen strings
for (int i = 0; i < 12; i ++) {
[stringsArray addObject:tempStr];
}
// Now you can use them by accessing the array
[self doSomethingWithString:[stringsArray objectAtIndex:8]];
Instead of having dozens of strings that have the same value, could you make a single static global string and reference that? If you need to change it to separate values later, use instance variables that are initialized to the global string.
This sounds like your model is not very good at all. Since you want to initialize all of your strings to the same value they are obviously related and probably should be modeled as an array like iPhoneDevProf described. That makes other things a lot easier too, you can move other code that is repeated for every string into a loop.
If the value is known when you are compiling the code AND it is not going to change after subsequent application sessions then you can use a simple #define.
#define MY_DEFAULT_STRING #"THE DEFAULT STRING"
Now all you have to do is the following.
{
NSString *myString1 = MY_DEFAULT_STRING;
NSString *myString2 = MY_DEFAULT_STRING;
....
NSString *myStringN = MY_DEFAULT_STRING;
}
If all the strings are in the same code file, just put the define at the top. If the strings are in separate code files, then it could be put into your precompiled header. Having a constants file is usually better.
Using constant extern NSString would probably be more correct, but this is simple and easy to do.

iPhone, objective c reassign and return pointer of method

Hey guys, lately I have been asking quite a few questions about memory management on the iPhone. Fortunately things are getting clearer. But I still struggle when it gets more complex: So is there something wrong with this in terms of memory mangement? My question and suggestions are in the comments...
//I get a text from a textfield
NSString *text = [[NSString alloc]initWithString:txtField.text];
NSMutableString *newText = [self replaceDynamicRegex:text];
[text release];
...
//The method replaces regex it finds in the text. The regex part is just pseudo code
//and I just interested in memory management
-(NSMutableString*)replaceDynamicRegex:(NSString*)txt{
NSString *currentTag = [NSString stringWithString:#"dynamiclyCreatedTag"];
//As long as we find a particuar regex (just pseuo code here) we replace it
while (currentTag != NULL) {
if([html stringByMatching:openingTag] == NULL){
break;
}
//regular expression
currentTag = [NSString stringWithString:[html stringByMatching:theRegex]];
//Get rid of the useless part of the currentTag pseudo code
NSString *uselessTagPart = #"uselessRegex";
//Reassignment of the pointer currentTag --> ok to do this? cause I did not alloc]init]?
//and instead used stringWithString wich then gets autoreleased
currentTag = [currentTag stringByReplacingOccurrencesOfRegex:uselessTagPart withString:#""];
//Reassignment of the pointer html --> Ok to do this? cause it is just a pointer and the
//object is being released after the method call (further up)
html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag];
}
//Do I need to autorelease this?
return html;
}
Your code looks correct memory-management-wise. Just remember, if you don't have call a method with alloc, new, retain, or copy in the method name, you don't have to worry about releasing.
One small point--your first 3 lines of code are redundant and inefficient. You shouldn't usually use initWithString--copy is usually a better choice when dealing with immutable objects, since behind the scenes a copy method can be replaced by a (less expensive) retain method. In your case, you don't even need to use copy--[self replaceDynamicRegex: txtField.text] will have the same result. Likewise, instead of [NSString stringWithString:[html stringByMatching:theRegex]], you can use simply use [html stringByMatching:theRegex] (since that method returns a new string).
Another note--html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] is incorrect. stringByReplacingOccurrencesOfRegex: returns an NSString, which can't be cast to an NSMutableString (you'll likely get a crash later on when you send a mutating method to the string). Instead, use [[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] mutableCopy]
Generally, when you see a method named xWithY, you can assume the string will be autorelease-d.
Therefore, you probably do not need to autorelease the value returned from -stringByReplacingOccurrencesOfRegex:withString:.
The rest of your code looks okay, to me.