Reputation: 846
I have two UIViewControllers
.In A ViewController
I have code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"ToResetPwd_NumberSegue"])
{
ResetPwdBySmsCodeViewController* vc = (ResetPwdBySmsCodeViewController*)[segue destinationViewController];
vc.phone_no = _TF_phoneOrEmail.text;//TF_phoneOrEmail is a UITextField
vc.test = @"dagaga";
}
}
In B .h I have code
@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (weak, nonatomic) NSString *phone_no;
@property (weak, nonatomic) NSString *test;
@end
In B .m
I can get the value of _test
,but not _phone_no
I am sure that vc.phone
is well in the prepareForSegue
Upvotes: 3
Views: 577
Reputation: 69027
You should declare the 2 properties in B ViewController as strong
or even better as copy
:
@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (strong, nonatomic) NSString *phone_no;
@property (strong, nonatomic) NSString *test;
@end
The reason why you can get _test
is that you are assigning it a literal string value, which is allocated by the compiler in a specific memory area. It is thus never deallocated and the weak
variable will indefinitely point at it (until you explicitly assign a new value to _test
, that is.)
On the other hand, you assign vc.phone_no
a property from another object that might not exist anymore when you access the weak
property (since a weak
property is nil-ed when the object it points to is deallocated.) Hence the need for strong
or copy
.
Upvotes: 7
Reputation:
You need to make your properties either strong or copy to claim ownership for the memory. You have them set to weak, which means you don't claim ownership and the data will disappear if no other variable has a strong reference to the data.
You always want to use copy for NSString objects because there is a mutable version of NSString, which means that your data could be changed without you realizing it.
@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (copy, nonatomic) NSString *phone_no;
@property (copy, nonatomic) NSString *test;
@end
Upvotes: 1
Reputation: 1819
Adding to @sergio response, I want to explain why the first one _TF_phoneOrEmail
did not work, but the second one did. This you will find only in case of String
and NSString
's.
Your _TF_phoneOrEmail
is an object created on runtime. The compiler generates code (instructions) in allocing, initing and incrementing reference count. Hence while you navigate from one controller to another since you are assigning a weak
reference, the reference count is not incremented. (You should rather try with assign
or copy
like @sergio has mentioned).
On the other hand, when you declare test
, the pointers are generated by compilers, but take the @"dagga"
object. This is interesting. This is a inbuilt optimisation in C, that when you declare a string (Note: not a String
instance) the instructions to create the new object instance of String
holding the value (@"dagga"
) are not generated. If you have come across process and threads internals, you will realise there is a memory segment called Code
in the process memory. The process (which basically executes the instructions generated by compiler) itself, doesn't have enough permissions to write to this memory: it can only read from it. The String
object (whose instructions are not generated by the compiler) is created in this memory. It's not exactly a object, its just a direct memory holding the value(@"dagga"
).
So even, @sergio was wrong when he mentioned "until you explicitly change its value, that is". You cannot. Try manipulating the string (_test) and your app will crash.
If you had declared it as [NSString stringWithString:@"dagga"]
, the compiler would have generated the instructions to create an object instance in heap/stack memory, but you declared as a literal, which cannot be deallocated at any executing time of the process.
Hope I'm clear.
Upvotes: 1