iOS ARC - 弱引用和强引用属性

5

我在尝试理解ARC的工作方式,就我所知,我可能在这里做错了些什么。这是我正在使用的代码:

接口:

@interface ViewController : UIViewController{

}

@property (strong, nonatomic) NSString * myString ; 
@property (weak, nonatomic) NSString * myPointer ;

实施:

 - (void)viewDidLoad{

     [super viewDidLoad];
     self.myString = @"Hello world!" ; // myString is strong
     self.myPointer = self.myString ; // myPointer var is weak

     [self performSelector:@selector(makeNilMyValue) withObject:nil afterDelay:1];    
     [self performSelector:@selector(printValues) withObject:nil afterDelay:2];    
}

 - (void) makeNilMyValue{
     self.myString = nil ; 
}

 - (void) printValues{
     NSLog(@"myString: %@", self.myString) ;
     NSLog(@"myPointer: %@", self.myPointer) ; 
 }

执行完这段代码后,我得到了:
2012-02-26 11:40:41.652 test1[933:207] myString: (null)

2012-02-26 11:40:41.653 test1[933:207] myPointer: Hello world!

如果我没记错,由于myPointer是弱引用,它不应该保留对象的内容。因此,它应该显示nil而不是“Hello World!”。

我做错了什么?

根据Caleb的答案,我又创建了另一个弱指针,请见下面的代码:

- (void)viewDidLoad{
    [super viewDidLoad];
    self.myString = @"Hello world!" ; // myString is strong
    self.myPointer = self.myString ; // myPointer var is weak
    self.myPointer2 = self.myString ; // myPointer2 var is weak

    [self performSelector:@selector(makeNilMyValue) withObject:nil afterDelay:1];    
    [self performSelector:@selector(printValues) withObject:nil afterDelay:2];    
}

- (void) makeNilMyValue{
    self.myPointer2 = @"value changed!" ;
    self.myString = nil ;

}

- (void) printValues{
    NSLog(@"myString: %@", self.myString) ;
    NSLog(@"myPointer: %@", self.myPointer) ;
}

重点是我仍然得到了与之前相同的答案:
2012-02-26 12:08:13.426 test1[1333:207] myString: (null)
2012-02-26 12:08:13.427 test1[1333:207] myPointer: Hello world!
2个回答

8

正如Caleb所指出的,对于这个例子使用一个常量NSString并不是一个好主意。

在源代码中创建字符串对象的最简单方法是使用Objective-C @"..."结构:

NSString *temp = @"/tmp/scratch"; 注意,当以这种方式创建字符串常量时,应避免使用除7位ASCII字符以外的任何内容。这样的对象在编译时创建,并在整个程序执行期间存在。编译器会使这些对象常量在每个模块上唯一,并且它们永远不会被释放,尽管您可以像处理其他对象一样保留和释放它们。您也可以像处理其他字符串一样直接向字符串常量发送消息:

BOOL same = [@"comparison" isEqualToString:myString];

文档解释了常量字符串永远不会消失。

请尝试使用其他内容进行实验。我尝试使用NSObject并产生了预期的结果。

界面:

@interface ViewController : UIViewController

@property (strong, nonatomic) NSObject * myString; 
@property (weak, nonatomic) NSObject * myPointer;

@end

实现:

@implementation ViewController

@synthesize myString = _myString;
@synthesize myPointer = _myPointer;

- (void)viewDidLoad{

    [super viewDidLoad];

    self.myString = [[NSObject alloc] init];
    self.myPointer = self.myString;
    self.myString = nil; 
    NSLog(@"myString: %@", self.myString);
    NSLog(@"myPointer: %@", self.myPointer);
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

@end

当没有强指针指向内存时,弱引用会被设置为nil。这在文档中有所解释 - Apple Developerllvm

__weak指定了一个不会保留所引用对象的引用。当没有强引用指向该对象时,弱引用会被设置为nil。


5
因此,它应该显示 nil 而不是“Hello World!”。

常量字符串永远不会被解除分配,因此您的 `@"Hello World!" 永远不会消失。这就是为什么您的弱引用从未设置为nil的原因。

谢谢你的回答,Caleb。那很有道理,不过我创建了另一个弱指针来测试你所说的。不幸的是,正如你所看到的,它并没有起作用。 - RGML
@Arkyxperience 你期望发生什么? - Caleb
5
当弱引用的目标对象被释放时,该引用会被设置为nil。这是ARC的一个特性--合成的弱引用属性永远不会持有悬空指针。 - FellowMD

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