6

问题

我正在迁移一些遗留代码(iOS 5 之前),我在其中延迟加载一些readonly属性。我想用 ARC 将此代码更新到 iOS 5+。但我只是了解ARC。

。H

@property (nonatomic, retain, readonly) NSDateFormatter *timeFormatter;

.m

- (NSDateFormatter *)timeFormatter {
    if (timeFormatter == nil) {
        timeFormatter = [[NSDateFormatter alloc] init];
        [timeFormatter setDateFormat:@"h:mm a"];
    }

    return timeFormatter;
}

我试过的

我试图简单地更新我的代码,但收到一个:Assignment to readonly property

。H

@property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;

.m

- (NSDateFormatter *)timeFormatter {
    if (self.timeFormatter == nil) {
        self.timeFormatter = [[NSDateFormatter alloc] init];
        [self.timeFormatter setDateFormat:@"h:mm a"];
    }

    return self.timeFormatter;
}

我还回顾了:

问题

readonly使用 ARC 在 iOS 5+ 中延迟加载属性的正确方法是什么?非常感谢.h.m的代码示例。

4

2 回答 2

14

对于自定义(惰性)getter 方法,您必须直接访问实例变量(无论您是否使用 ARC)。因此,您应该将属性综合为

@synthesize timeFormatter = _timeFormatter;

那么你的getter方法是

- (NSDateFormatter *)timeFormatter {
    if (_timeFormatter == nil) {
        _timeFormatter = [[NSDateFormatter alloc] init];
        [_timeFormatter setDateFormat:@"h:mm a"];
    }

    return _timeFormatter;
}

如果同时从多个线程访问该属性,则只需添加一些同步机制,这也与 ARC 无关。

备注:较新的 Xcode 版本可以自动创建@synthesize语句并为实例变量使用下划线前缀。但是,在这种情况下,由于属性是只读的并且您提供了 getter 方法,Xcode 不会自动合成属性。)

添加:为方便起见,这是一个完整的代码示例:

MyClass.h:

#import <Foundation/Foundation.h>

@interface MyClass : NSObject
@property (nonatomic, strong, readonly) NSDateFormatter *timeFormatter;
@end

我的班级.m:

#import "MyClass.h"

@implementation MyClass
@synthesize timeFormatter = _timeFormatter;

- (NSDateFormatter *)timeFormatter {
    if (_timeFormatter == nil) {
        _timeFormatter = [[NSDateFormatter alloc] init];
        [_timeFormatter setDateFormat:@"h:mm a"];
    }

    return _timeFormatter;
}

@end

更多信息:事实上,timeFormatter如果属性被合成为

@synthesize timeFormatter; // or: @synthesize timeFormatter = timeFormatter;

您犯的唯一“错误”是在 getter 方法中替换timeFormatter为。self.timeFormatter这会产生两个问题:

  • 在 getter 方法内部读取self.timeFormatter会导致无限递归。
  • self.timeFormatter由于只读属性,不允许设置。

因此,如果您只保留timeFormattergetter 方法(使用timeFormatter方法内的实例变量),那么它也适用于 ARC。

我仍然建议在我的代码示例中为属性的实例变量添加下划线前缀,因为 Xcode 对自动合成属性的处理方式相同。

(我希望这会有所帮助,并且不会增加混乱!)

于 2012-12-02T15:53:33.217 回答
7

只读属性就是:只读。不应该有二传手参与。好的部分是,如果您将类扩展中的变量(通常带有一对空括号)重新声明为 readwrite(甚至只是完全删除 readonly),那么您可以在 .m 中分配给它,但是类导入它会将其视为只读。

@interface MyClass ()

@property (nonatomic, strong) NSDateFormatter *timeFormatter;

@end

这种重新声明允许以更简洁的方式在内部访问和改变属性,而无需求助于脆弱的 iVar 综合(现在编译器已经为您完成了它,这已成为一种古老)。您可以,或者当然,仍然可以使用 iVar,如另一个答案中所示,但 -init 或合成 getter 之外的 iVar 访问是不必要的。 *

*正如Martin正确指出的那样,即使您的分配成功,您仍然会导致无限递归,因此iVar访问是必要的,除非您明确声明getter,否则您可以使用属性访问。

于 2012-12-02T15:39:21.917 回答