Objective-C - why adding two string is causing the crash? - ios

Appending new string to old string is causing crash.
(abnormally works if i do as like this StructIOS.server = #""; StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"];).
struct.h:
struct iOS {
__unsafe_unretained NSString *input_url;
__unsafe_unretained NSString *use_url;
__unsafe_unretained NSString *server;
};
struct iOS StructIOS;
ViewController.m:
StructIOS.use_url = #"relay/pincode/apicode/accesskey/1/2/3/99/../900";
NSArray *work_array = [StructIOS.use_url componentsSeparatedByString:#"/"];
StructIOS.server = [work_array objectAtIndex:0];
if([StructIOS.server length] > 0) {
NSLog(#">>> 4: %#", StructIOS.server); // OK!!
StructIOS.server = [StructIOS.server stringByAppendingString:#".stackoverflow.com"]; // FAIL!!
NSLog(#">>> 5: %#", StructIOS.server);
}
Output:
>>> 4: relay
crash
Expected output:
>>> 5: relay.stackoverflow.com
EDIT: following way worked without crash
NSString *fool_ios;
// read from NSString type
StructIOS.server = fool_ios;
// save to NSString type
fool_ios = StructIOS.server;

The answer is two-fold:
Don't store objects in Objective-C Structs. ARC won't manage the memory for them.
Don't use unsafe_unretained unless you understand exactly what it does and exactly why you need it.
Simply make your variables instance variables of your class. That will make them strong, which is what you want.
EDIT:
Note that in Swift, it is valid to store objects in a Struct. Swift is able to memory manage them inside a struct, where C does not.
Any time the compiler forces you to use __unsafe_unretained, you're likely doing something wrong. (There are exceptions to that, but at your level of understanding, you should pretend that __unsafe_unretained doesn't exist.)

Why are they __unsafe_unretailed?
componentsSeparatedByString() will presumably internally be creating some substrings which you are not taking ownership of due to using __unsafe_unretained, thus they are being deleted when componentsSeparatedByString function got out of scope.
The log at line 4 is working purely though chance and good luck as the string is deallocated but still there at that memory location.
If you rewrite the struct as a simple class (which inherits from NSObject) it should work.

Related

change property object will not affect property

I would like to verify something that I always use but when I think about it ... I get confused why it worked that way and I sure I read the explanation about it but I cant find it.
As far as I understand apple create their setter as something like this.
-(void)setString:(NSString *)value {
if (_string != value) {
[_string release];
_string = [value retain];
}
}
Now usually I create properties like this.
#property (nonatomic) NSString *string;
#synthesize string = _string;
The question is about next code:
NSString *s = #"Should be deleted";
[self setString:s];
NSLog(#"string check111 =%#",self.string);
s = NULL;
NSLog(#"string check222=%#",self.string);
The same output will be generated. From the setter I can see that my property points on the object that I changed but the property value will be the same.That situation triggers another question (if it works like that why would I need copy attribute).
Can someone provide a short explanation about it? (or concrete link to read).
Tnx A Lot. (I think my question may be already asked in the forum )
This has no effect because you are changing the object to which s points to.
This diagram probably explains it better, originally you have something like this:
Changing the point of s will not affect _string.
The idea of setting the property to copy is in case you set your string property to a mutable string and then change the content of it. See this question.
I guess it would be something like this
NSString *s = #"Should be deleted"; // create autoreleased string
[self setString:s]; // retain string
NSLog(#"string check111 =%#",self.string);
s = NULL; // reset pointer value to null. This operation doesn't affect string object
NSLog(#"string check222=%#",self.string);
// string's retain counter will be decreased by autorelease pool later

Confusion on memory address for NSString between view Controllers

In my child view controller, I have a property defined as:
#property (nonatomic, copy) NSString *name;
In view controller A, the Parent, I have the following:
NSString *temp = currency.name; //This is because currency is a Core Data Managed Object.
//I wanted to make sure it wasn't a confounding factor.
childViewController.name = temp;
if(childViewController.name == temp)
NSLog(#"I am surprised");
The problem is that if statement finds equivalency and the "I am surprised" is printed. I thought that == should be checking if they're the same object, and that the use of copy in the property declaration should ensure the setter is making a copy. I checked in the debugger and they are both pointing to the same string. (Which I believe is immutable, which may be why this is happening?)
The same thing happens even if I write childViewController.name = [temp copy];, which I find shocking!
Can anyone explain what is going on here?
Edit: I removed a bit here on worrying about a circular reference which I realized wasn't a concern.
This is an optimization.
For immutable objects, it's superfluous to create an actual copy, so - copy is often implemented as a simple retain, i. e.
- (id)copy
{
[self retain];
return self;
}
Try assigning a mutable object (e. g. NSMutableString) to the property, and you will get the "expected" behavior.

EXC_BAD_ACCESS error when changing views with PresentModalViewController

I'm trying to switch views in my app using this chunk of code:
self->variable1 = [[NSNumber alloc] initWithInt:0];
self->variable2 = [[NSMutableArray arrayWithCapacity:1];
self->variable3 = [[NSMutableArray arrayWithCapacity:1];
[self presentModalViewController:titleScreen animated:YES];
If I comment out all of the allocated variable lines, the code works fine. If it leave just 1 line in the code crashes with the "EXC_BAD_ACCESS" error. Why is this happening? The variables aren't being used at all, just declared for later use. I'm not getting any compile errors on the lines either. What am I doing wrong?
UPDATE:
Thank you everyone for the help. I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem. After a long time of fiddling I fixed it. I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
and it worked! Can someone explain why this worked and the first line didn't?
Update:
Thank you Peter Hosey for showing me my evil ways. This time I'm pretty sure it's fixed. I was storing my variable Releases in
-(void)release
I didn't realize xCode will release when it needs to. I moved all the variable releases to
-(void)Destroy
so I can release everything on MY command. Now the code works. Thanks again!
I suggest that you declare variable1, variable2, and variable3 as properties, not instance variables. Then, use self.variable1, self.variable2, and self.variable3 to access them.
The dot syntax (self.variable1, etc.) uses the memory management policy you declared on each property; the arrow syntax (self->variable1, etc.) will access the variables directly. The crash is because you created two arrays in away that doesn't leave you owning them, and then did not assign the arrays to a property that would retain them.
You may also want to upgrade your project to use ARC. Then there is no memory-management difference; assigning to the instance variables rather than the properties will not cause the object to be prematurely released, because ARC considers instance variables to be ownerships by default. You may still want to switch to using properties after you switch to ARC, but not to prevent a crash.
In response to your edit:
I change the way I declare my variables to #property/#synth to clean up my code, but it didn't fix the problem.
Then something else was wrong.
You never did say much about the problem itself. You said you got an EXC_BAD_ACCESS, but not what statement triggered the crash or on what grounds you blamed it on the code you showed.
I changed the code from this:
self.variable1 = [[NSNumber alloc] initWithInt:0];
That's the correct code, though. That's what you should be using.
to this:
self.variable1 = [NSNumber alloc];
[self.variable1 initWithInt:0];
Noooo! That code is wrong, wrong, wrong, on multiple levels.
init methods (including initWithWhatever: methods) are not guaranteed to return the same object you sent the message to. NSNumber's initWithInt: very probably doesn't.
That object creates an uninitialized NSNumber object and assigns that to the property. Then it sends initWithInt: to that object, which will return an initialized object, which can be and very probably will be a different object. Now you are holding an uninitialized object (which you will try to use later) and have dropped the initialized object on the floor.
Never, ever, ever send alloc and init(With…) in separate expressions. Always send them in the same expression. No exceptions. Otherwise, you risk holding the uninitialized object rather than the initialized object. In your case (with NSNumbers), that is almost certainly what will happen.
What you should be doing is declaring and synthesizing a strong property that owns the NSNumber object, and creating the NSNumber object in a single statement: either [[NSNumber alloc] initWithInt:] or [NSNumber numberWithInt:]. If you're not using ARC, you'll want the latter, since the property will retain the object. If you are using ARC, they're effectively equivalent.
And if you get a crash with that code, then something else is wrong, so please tell us—either in this question or in a new question—about the crash so we can help you find the true cause of it.
variable2 and variable3 are being autoreleased before you actually access them (presumably) later after presenting the modal view.
At the very least change the lines to:
self->variable2 = [[NSMutableArray arrayWithCapacity:1] retain];
self->variable3 = [[NSMutableArray arrayWithCapacity:1] retain];
or
self->variable2 = [[NSMutableArray alloc] initWithCapacity:1];
self->variable3 = [[NSMutableArray alloc] initWithCapacity:1];
variable1 should be fine.
Best would be to use #property and #synthesize so you can use dot notation:
.h
#interface MyClass : SuperClass
#property (nonatomic,retain) NSMutableArray *variable2;
#property (nonatomic,retain) NSMutableArray *variable3;
#end
.m
#implementation MyClass
#synthesize variable2,varible3;
- (void)foo {
self.variable2 = [NSMutableArray arrayWithCapacity:1];
self.variable3 = [NSMutableArray arrayWithCapacity:1];
}
#end
By default, all instance variables in objective-c have protected scope. So unless you have explicitly declared them public in your interface file as:
#interface MYClass {
#public
NSNumber *variable1;
NSMutableArray *variable2;
NSMutableArray *variable3;
}
//...
#end
then they will not be accessible using the struct dereferencing operator. This is likely the cause of those EXC_BAD_ACCESS errors.

What is difference between initilizing an NSString simply and with retain?

I want to know that difference between following two lines
name1 = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)] retain];
name1 = [NSString stringWithUTF8String:(char *)sqlite3_column_text(compiledStatement,1)];
What will be effect on name1 if I do use retain at the last,
I face once problem, and couldn't use name1 in a method that is being call by NSTimer, and when I use retain, they it worked fine for me.
If I do call value from database in viewDidLoad, and use in a method that is being called by NSTimer after each second, then it will give bad-exec, but when I do use retain then it will work properly,
I want to know the reason
Here is the difference
- (void)func1 {
name1 = [[NSString stringWithUTF8String:...] retain];
name2 = [NSString stringWithUTF8String:...];
}
- (void)func2 {
NSLog(#"%#", name1); //OK, name1 is still there
NSLog(#"%#", name2); //Would be crashed because name2 could be released anytime after func1 is finished.
}
I wrote this answer to another question, but it explains what you're asking:
Objects in objective c have a retain count. If this retain count is greater that 0 when the object goes out of scope (when you stop using it), it leaks.
The following things increase the retain count
[[alloc] init]
new
copy
[retain]
adding an object to an array
adding an object as a child (e.g. views)
There are likely more, but you don't appear to use any others in your code
The following decrease the retain count
[release]
removing an object from an array
if you dealloc an array, all of its objects are released
You should go through your code and ensure each of the retains or additions to an array are matched with a corresponding release. (You can release member variables in the dealloc method).
Another user made a valid point that my answer doesn't
Once you add an object to an array, it takes ownership and will release the object when it is done with it. All you need to do is make sure you release anything you own according to the memory management rules
There are also autorelease objects, have a look at this example;
-(init){
...
stagePickerArray = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++)
{
//this string is autoreleased, you don't have call release on it.
//methods with the format [CLASS CLASSwithsomething] tend to be autorelease
NSString *s = [NSString stringWithFormat:#"%d", i);
[stagePickerArray addObject:s];
}
...
}
Your issue is that when you come to use your string later, it has a retain count of zero and has been released. By calling retain on it, you're saying 'I want to use this later'. Don't forget to match every retain with a release or you're objects will 'leak'
I bet your code wouldn't crash if your name1 was a property - either (nonatomic, retain) or just (copy) depending on your needs.
Second condition is to have name1 initialized to sth meaningful at the time your other function tries to do sth with it.
EDIT:
With a property you'd have to use synthesized setter in this case with: self.name1 = #"your string";.
Normally you don't have to manually retain/release a string created with stringWith... methods since there's nothing you created in memory yourself by using explicit alloc. Also please note that with code:
NSString *str = [NSString stringWithUTF8String:#"your string"];
your str (if not used to set a property) will stop being available when the function gets out of scope (iOS eventloop will autorelease it).

Objective C NSString* property retain count oddity

I have the following example class:
Test.h:
#interface Test : UIButton {
NSString *value;
}
- (id)initWithValue:(NSString *)newValue;
#property(copy) NSString *value;
Test.m:
#implementation Test
#synthesize value;
- (id)initWithValue:(NSString *)newValue {
[super init];
NSLog(#"before nil value has retain count of %d", [value retainCount]);
value = nil;
NSLog(#"on nil value has retain count of %d", [value retainCount]);
value = newValue;
NSLog(#"after init value has retain count of %d", [value retainCount]);
return self;
}
Which produces the following output:
2008-12-31 09:31:41.755 Concentration[18604:20b] before nil value has retain count of 0
2008-12-31 09:31:41.756 Concentration[18604:20b] on nil value has retain count of 0
2008-12-31 09:31:41.757 Concentration[18604:20b] after init value has retain count of 2147483647
I am calling it like:
Test *test = [[Test alloc] initWithValue:#"some text"];
Shouldn't value have a retain count of 1? What am I missing?
Thanks for your help.
Don't look at retain counts. They're not useful and will only mislead you — you can't be certain that nothing else is retaining an object, that an object you get from somewhere isn't shared.
Instead, concentrate on object ownership and follow the Cocoa memory management rules to the letter. That way your memory management will be correct no matter what optimizations Cocoa may be doing behind the scenes for you. (For example, implementing -copy as just -retain for immutable objects.)
Furthermore, it's critical to understand the difference between properties of your objects and instance variables within your objects. In your question's code, you are assigning a value to an instance variable. That instance variable is just that: a variable. Assigning to it will behave like any other variable assignment. To use the property, you must use either dot syntax or bracket syntax to actually invoke the property's setter method:
self.value = newValue; // this is exactly equivalent to the next line
[self setValue:newValue]; // this is exactly equivalent to the previous line
The code generated for the dot syntax and the bracket syntax is identical, and neither will access the instance variable directly.
You are passing in a literal string. The compiler probably allocates it in static memory and sets the retain count to the maximum possible value.
Try a dynamically allocated string instead and see what happens.
NSString* string = [[NSString alloc] initWithString: #"some text"];
Test* test = [[Test alloc] initWithValue: string];
You've got a reference to an immutable string. Assignment doesn't need to copy the value (the string data) since it's immutable. If you do a mutable operation, like value = [newValue uppercaseString] then it should copy the bits into value, and value's retain count incremented.
You're passing in a string constant, which can't really be deallocated. I think that 2147483647 is probably UINT_MAX, which basically means that the object can't be released.
I think you want to do this:
self.value = newValue;
which will invoke the property setter and cause the copy to occur. "value = newValue" simply assigns a pointer value to the instance variable.
You shouldn't be paying attention to the retain counts, just follow the Cocoa memory management rules. http://iamleeg.blogspot.com/2008/12/cocoa-memory-management.html
hmm.. we're getting closer.
it appears that newValue's retain count is also 2147483647.
I tried dynamically allocating the string instead with the same retain count results.
I found a helpful article here: http://www.cocoadev.com/index.pl?NSString
FTA:
Does the NSString returned by #"" need to be released, or is it autoreleased?
Neither. #""-strings are of class NSConstantString?, and thus act like atoms in lisp; they hang around. That is, if you use #"cow" in two separate places in your code, they will be referencing the very same object.
I don't think -release or -autorelease does anything to either of them.
If I have "copy" on the property though, shouldn't it copy the contents of the target memory into new memory with a retain count of 1? It would seem the copy attribute does nothing in this case?
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
char *cstr = "this is a c string";
NSString *str = [[NSString alloc] initWithUTF8String:cstr];
NSLog(#"rc1: %d", [str retainCount]);
[pool drain];
return 0;
}
If you run the above code, it will display a retain count of 1
In Cocoa, many immutable objects will simply retain themselves when you ask for a copy within the same zone. If the object is guaranteed not to change (i.e. its immutableness) then an exact duplicate is redundant.
In Objective-C, the constant string class is separate to Cocoa's NSString class, although it may be a subclass of NSString (I'm not too sure). This constant string class may override NSObject's methods like retain, release and dealloc so that they do nothing, and also override retainCount so that it always returns the same number, UINT_MAX or so. This is because an Objective-C constant string is created in static memory. It must have the overall general behaviour of a Cocoa object (when using Cocoa) so that it can be added to arrays, used as keys to a dictionary etc, except in regards to its memory management, since it was allocated differently.
Disclaimer: I don't actually know what I'm talking about.

Resources