__weak NSString * text = self.textField.text具有不一致的行为

时间:2015-11-04 07:17:57

标签: objective-c

我想我可能犯了一个愚蠢的错误,但我无法弄清楚原因:

我有一个方法和Block来处理一些网络API,如:

-(IBAction)confirm:(id)sender {         
    __weak typeof(self) weakSelf = self;
    __weak NSString *anotherNumber = self.nextPhoneTextField.text;
    [SharedInstance bindNewPhoneNumber:self.nextPhoneTextField.text pinCode:self.verifyCodeTextField.text sucess:^(id result) {

      // update phone number
      SharedInstance.phoneNumber = anotherNumber;

    }]; 
}

在阻止之前,我可以看到newNumber正确值,

但是,当调用块时,newNumber为nil,而不是文本。但是我能够打印weakSelf.nextPhoneTextField.text,但没有改变。

感谢任何解释!

更新

创建示例项目后,我发现它不可重现。弱字符串指针具有有效文本。然后我开始调试它,我发现了,

为了避免使用new关键字,我将指针名称更改为anotherNumber

在我的真实项目中,在致电__weak NSString *anotherNumber = self.nextPhoneTextField.text;时,anotherNumber有一个新地址,而不是self.nextPhoneTextField.text;地址:

(lldb) p anotherNumber
(__NSCFString *) $2 = 0x00007f88b3ff2960 @"12345678901"
(lldb) p self.nextPhoneTextField.text
(__NSCFString *) $3 = 0x00007f88b15f8690 @"12345678901"

但是在示例项目中,我有类似的功能,

- (void)clickBlock:(void (^)(NSString * string))block {
    if (block) {
        block(@"haha");
    }
}

- (IBAction)clicked:(id)sender {
    __weak typeof(self) weakSelf = self;
    __weak NSString *text = self.textField.text;

    [self clickBlock:^(NSString *string) {
        NSLog(text);
        NSLog(string);
    }];
}

它是相同的地址:

(lldb) p text
(NSTaggedPointerString *) $2 = 0xa000000747365744 @"test"
(lldb) p self.textField.text
(NSTaggedPointerString *) $3 = 0xa000000747365744 @"test"

并且班级类型也改变了......寻找答案!!!

另一次更新:

我删除了块,只需创建两个弱指针,其中包含一些字符串,如" hello"和#34; 12345678901",形成者具有相同的地址并标记为NSTaggedPointerString,但后者具有不同的地址并标记为NSCFString

在我看来,一旦文本达到特定长度,它将具有NSCFString和不同的地址,并且在一些测试之后,赏金是9.一旦超过9个单词,它将是NSCFString,在iOS 9.1 iPhone 6S模拟器上测试。

在iOS 8.4模拟器上,所有不同长度的字符串都会产生不同的mem地址和NSCFString

示例项目:https://github.com/liuxuan30/WeakStringPointer

1 个答案:

答案 0 :(得分:0)

__weak NSString *anotherNumber = self.nextPhoneTextField.text;

使用此行,NSString 按值复制而不是引用,因此在将NSString分配给另一个NSString后,它会创建它的新副本并创建引用到新创建的副本而不是原始副本,并且因为引用很弱,在当前函数脱离上下文后对象将为nil,

如果您尝试更改文本字段的文本,则更改textFields文本,而不是anotherNumber对象。

NSString *test = self.nextPhoneTextField.text;
self.nextPhoneTextField.text = @"Something else";
NSSLog(@"Test object contains %@ , the textField contains %@ ",test,self.nextPhoneTextField.text);

您的代码确实如下:

  1. NSString
  2. 创建新的复制self.nextPhoneTextField.text
  3. 将新副本NSString转为anotherNumber
  4. 由于anotherNumber__weak不会保留对象(NSString),它将保留__weak对此对象的引用,在此功能脱离上下文后,它变为零。
  5. 要确认此行为,您可以在设置其值并在不同的上下文

    后直接记录anotherNumber
    __weak NSString *anotherNumber = self.nextPhoneTextField.text;
    NSString *strongAnotherNumber = self.nextPhoneTextField.text;
    NSLog(@"Weak number - %@ , strong - %@",anotherNumber,strongAnotherNumber);
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"Block Weak number - %@ , strong - %@",anotherNumber,strongAnotherNumber);
    });
    

    请同时查看Why do weak NSString properties not get released in iOS?