I am new here, and already searched related articles like "Is “self” necessary?" and "Setting an Objective-C class property without using a self reference" However i still can't get a clear answer which can explain my case.
I have a simple class and my UI has two textfield and one button, here is the code:
@interface testViewController : UIViewController {
NSString *teststring_A;
NSString *teststring_B;
IBOutlet UITextField *textfield_1;
IBOutlet UITextField *textfield_2;
}
@property (nonatomic, retain) NSString *teststring_A;
@property (nonatomic, retain) NSString *teststring_B;
- (IBAction)action1:(id)sender;
- (IBAction)action2:(id)sender;
@end
@implementation testViewController
@synthesize teststring_A;
@synthesize teststring_B;
- (void)dealloc {
[super dealloc];
}
- (IBAction)action1:sender
{
teststring_A = textfield_1.text ;
NSLog(@"teststring_A in action 1 is : %@\n", teststring_A);
teststring_B = textfield_2.text ;
NSLog(@"teststring_B in action 1 is : %@\n", teststring_B);
}
- (IBAction)action2:(id)sender
{
NSLog(@"teststring_A in action 2 is : %@\n", teststring_A);
NSLog(@"teststring_B in action 2 is : %@\n", teststring_B);
}
the output is :
2010-11-19 15:32:14.827 test[419:207] teststring_A in action 1 is : 123
2010-11-19 15:32:14.829 test[419:207] teststring_B in action 1 is : 456
2010-11-19 15:32:14.927 test[419:207] teststring_A in action 2 is : 123
2010-11-19 15:32:14.929 test[419:207] teststring_B in ac开发者_JS百科tion 2 is : {(
>
)}
And when click button, it triggers action1 first then action2. My problem is... in action2, the value of teststring_B becomes incorrect, sometimes the application even crashes. What confuses me is (1) why is the value of teststring_A correct??? (2) teststring_B is assigned by textfield_2.text which is not created with 'alloc', so suppose the pointer should exist all the time. then why teststring_B's value becomes incorrect in action2 ??? (3) in dealloc, I should release teststring_A and teststring_B, right? (i think so )
All I know is if I add 'self.', like 'self.teststring_B = textfield_2.text;' then there won't be problem. the value will be correct. So I would like to know the technical reason.
You are confusing variables and properties. Properties are backed by variables, but in reality they are methods.
Here, you define a property named teststring_B
which retains anything that gets assigned to it (and releases the old value). The equivalent methods would look like this (simplified):
- (NSString *)teststring_B {
// Return the content of the variable teststring_B.
return teststring_B;
}
- (void)setTeststring_B:(NSString *)val {
// Retain new value.
[val retain];
// Release old value in variable teststring_B
[teststring_B release];
// Assign the new, retained value to variable teststring_B
teststring_B = val;
}
You can now use the property in two ways: either with [self setTeststring_B:foo];
or with self.teststring_B = foo;
. The important point is that the later is just a convenient way of writing, the compiler will translate it into the first form, that is the compiler will turn the self.foo = bar;
lines into [self setFoo:bar];
.
Now that we have this explained, on to your crash: you've got a string value which is most likely autoreleased. Now you just plain assign it to the variable teststring_B
, not the property. And you forgot to retain the value. The property would have retained that value for you.
Now the assigned value was autoreleased (it didn't know you've got a variable still pointing to it) and later a new object came to life at the exact same memory location (if you're lucky). In any case, the teststring_B
variable is now not pointing to the text as you thought it would, but to some random object (or to garbage).
There are two ways to fix this:
// First retain, then release; it might be the same object
// and if you would release it first its retain count might
// drop to 0 and get cleaned up before you can retain it again.
NSString *tmp = [textfield_2.text retain];
[teststring_B release];
teststring_B = tmp;
// Better !
self.teststring_B = textfield_2.text;
Accessing the variable directly without using the self will not retain it. So when you accessing it later the variable got auto-released and makes your application crash.
so you can write
1) [self setTeststring_B:textfield_2.text]; or
2) the dot syntax self.teststring_B = textfield_2.text; or
3) teststring_b = [textfield_2.text retain]
What you are doing now is simple assignment. That can cause a crash if the object teststring_A
or teststring_B
point to is deallocated; this is also called a dangling reference.
The reason only simple assignment is happening is because you aren't accessing the setters through the @property
semantics; you could get a retain
on those NSString
objects by doing self.teststring_A = textfield_1.text
instead.
However, you should be using copy
with NSString
properties. See: NSString property: copy or retain?
In other words, you want this:
@property (nonatomic, copy) NSString *teststring_A;
@property (nonatomic, copy) NSString *teststring_B;
and this:
self.teststring_A = textfield_1.text ;
self.teststring_B = textfield_1.text ;
精彩评论