为什么我不能通过 prepareForSegue 传递值?

3

我有两个UIViewControllers。在A ViewController中,我有以下代码:

- (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";
}

}

在B .h文件中,我有一段代码

@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (weak, nonatomic) NSString *phone_no;
@property (weak, nonatomic) NSString *test;
@end

在 B .m 中

我可以获取 _test 的值,但无法获取 _phone_no 的值

我确定在 prepareForSeguevc.phone 已经被正确设置


打印 _TF_phoneOrEmail.text 的值。 - Neil Galiaskarov
3个回答

7

在 B ViewController 中,您应该将这 2 个属性声明为 strong 或者更好地声明为 copy

@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (strong, nonatomic) NSString *phone_no;
@property (strong, nonatomic) NSString *test;
@end

你可以获得 _test 的原因是你为它分配了一个文字字符串的值,这个值被编译器分配在一个特定的内存区域,在这个内存区域中,这个值将永远不会被释放。因此,weak 变量将无限期地指向它(直到你明确地为 _test 分配一个新值)。另一方面,你为 vc.phone_no 分配了一个来自另一个对象的属性,当访问 weak 属性时,这个对象可能已经不存在了(因为 weak 属性在其指向的对象被释放时会被设置为 nil)。因此需要使用 strongcopy

你能告诉我为什么在UITableViewController中可以工作,因为我使用相同的方式传递值并成功了! - SeanChense
1
一个 UITableViewController 只会显示需要的单元格,你知道的。现在,可能发生的情况是你正在获取值的文本字段属于表视图控制器释放的单元格。简而言之,你无法控制单元格何时被释放... - sergio
@sergio,请查看我的回答。我认为你在一个小点上错了。请告诉我你的想法。 - Dunes Buggy
@iRaviiVooda:看起来你的回答总结为:文字永远不会被释放。这也是我在我的回答中所说的。另一方面,我看不出改变“test”值(即将不同的值分配给它)会造成任何伤害。它不会,只是它将指向一个不同的对象或者是nil... - sergio
@sergio:是的,如果你将不同的内存块分配给“_test”指针,它不会造成任何问题。但是,在分配其他内存之前,如果你尝试对当前内存执行任何突变操作,你将会崩溃。我认为我稍微误解了你的句子。但仍然有一点是我要补充到你的回答中。 - Dunes Buggy
@iRaviiVooda:我明白了。我修改了我的答案,以消除任何歧义。谢谢。 - sergio

1
你需要将属性设置为strong或copy,以声明对内存的所有权。你目前将它们设置为weak,这意味着你没有声明所有权,如果没有其他变量具有对数据的强引用,则数据将消失。
对于NSString对象,您始终要使用copy,因为NSString有一个可变版本,这意味着您的数据可能会在不知不觉中发生更改。
@interface ResetPwdBySmsCodeViewController : UIViewController<UITextFieldDelegate>
@property (copy, nonatomic) NSString *phone_no;
@property (copy, nonatomic) NSString *test;
@end

1
补充@sergio的回答,我想解释一下为什么第一个“_TF_phoneOrEmail”没有起作用,但第二个却有用。这只适用于“String”和“NSString”的情况。
您的“_TF_phoneOrEmail”是在运行时创建的对象。编译器生成代码(指令)来分配、初始化和增加引用计数。因此,当您从一个控制器导航到另一个控制器时,由于您分配了一个“弱”引用,引用计数不会增加。(您应该尝试使用“assign”或“copy”,就像@sergio所提到的那样)。
另一方面,当您声明test时,指针是由编译器生成的,但是使用@"dagga"对象。这很有趣。这是C语言中内置的优化,当您声明一个字符串(注意:不是String实例)时,不会生成创建新String对象实例的指令,该实例包含值(@"dagga")。如果您了解进程和线程内部原理,您将意识到进程内存中有一个名为Code的内存段。进程本身(基本上执行编译器生成的指令)没有足够的权限写入此内存:它只能从中读取。 String对象(其指令未由编译器生成)在此内存中创建。它不完全是一个对象,只是直接保存值(@"dagga")的内存。

因此,即使@sergio提到“直到您明确更改其值为止”,他也是错误的。你不能。尝试操作字符串(_test),您的应用程序将崩溃。

如果您将其声明为 [NSString stringWithString:@"dagga"],编译器将生成在堆栈内存中创建对象实例的指令,但您声明为文字值,该值无法在进程的任何执行时间释放。
希望我说得清楚。

我觉得我应该学习更多的英语 :(,我只会一点英语。 - SeanChense

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接