Code Bye

为什么init方法中官方推荐最好直接访问成员变量而不是通过setter?

今天看官方文档时看到一段话,理解不了,求指教。
原文:
You should always access the instance variables directly from within an initialization method because at the time a property is set, the rest of the object may not yet be completely initialized. Even if you don’t provide custom accessor methods or know of any side effects from within your own class, a future subclass may very well override the behavior.

尤其是because后面那段话,看不懂。

我个人觉得不要太在意这个,因为这更像是之前MRC的习惯(MRC下,dealloc里调用[self.name release]必然造成内存泄漏),ARC下哪怕是苹果自己的代码都没有遵守,给你一些示例:
AFNetworking的示例代码:
- (id)initWithCoder:(NSCoder *)decoder {
    self = [super initWithCoder:decoder];
    if (!self) {
        return nil;
    }

    self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];

    return self;
}
- (instancetype)initWithBaseURL:(NSURL *)url
           sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
    self = [super initWithSessionConfiguration:configuration];
    if (!self) {
        return nil;
    }

    // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
    if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
        url = [url URLByAppendingPathComponent:@""];
    }

    self.baseURL = url;

    self.requestSerializer = [AFHTTPRequestSerializer serializer];
    self.responseSerializer = [AFJSONResponseSerializer serializer];

    return self;
}

FLEX示例代码:

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.slider = [[UISlider alloc] init];
        self.slider.backgroundColor = self.backgroundColor;
        [self.slider addTarget:self action:@selector(sliderChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSubview:self.slider];
        
        self.valueLabel = [[UILabel alloc] init];
        self.valueLabel.backgroundColor = self.backgroundColor;
        self.valueLabel.font = [FLEXUtility defaultFontOfSize:14.0];
        self.valueLabel.textAlignment = NSTextAlignmentRight;
        [self addSubview:self.valueLabel];
        
        [self updateValueLabel];
    }
    return self;
}

苹果官方Demo:


- (id)initWithSourceType:(AssetBrowserSourceType)sourceType modalPresentation:(BOOL)modalPresentation;
{
    if ((self = [super initWithStyle:UITableViewStylePlain])) 
    {
        self.assetSources = sources;
        
        if ([sources count] == 1) {
            singleSourceTypeMode = YES;
            self.title = [[self.assetSources objectAtIndex:0] name];
        }
        else {
            self.title = NSLocalizedString(@"Media", nil);
        }
 
    }
    return self;
}

所以我觉得不用太在意这个,这个建议目前看起来似乎有一些不合时宜

谢谢版主哈,目前初学,不想被乱七八糟的中文书籍误导,留下难以磨灭的”印象”,所以直接看了官方文档,收获不少,但是也有很多疑问。。。
我个人对这个问题的理解是,自己写的setter方法中可能会有其他行为,而不是单纯的赋值,比如可能使用到其他成员变量的值。而在init中,有些成员变量都没初始化成有意义的值,然后使用setter的话,setter使用的也是没有意义的值,所以不是很好。这样理解你觉得make sense吗?

40分
引用 2 楼 a522256746 的回复:

谢谢版主哈,目前初学,不想被乱七八糟的中文书籍误导,留下难以磨灭的”印象”,所以直接看了官方文档,收获不少,但是也有很多疑问。。。
我个人对这个问题的理解是,自己写的setter方法中可能会有其他行为,而不是单纯的赋值,比如可能使用到其他成员变量的值。而在init中,有些成员变量都没初始化成有意义的值,然后使用setter的话,setter使用的也是没有意义的值,所以不是很好。这样理解你觉得make sense吗?

事实上我也经常在init里用setter,比如初始化一个变量的时候,给另一个变量也做一些操作,这样的行为,其实是与业务逻辑挂钩的。关键是Apple自己提供的许多Demo里也有这样的行为,我到是希望能看到几个“不接受”这个建议导致的问题。


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明为什么init方法中官方推荐最好直接访问成员变量而不是通过setter?