SeanChense
SeanChense

Reputation: 846

Why can't I pass value using prepareForSegue?

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

Answers (3)

sergio
sergio

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

user3826229
user3826229

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

Dunes Buggy
Dunes Buggy

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

Related Questions