加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

objective-c – 用init方法替换self是一种不好的做法吗?

发布时间:2020-12-16 07:05:39 所属栏目:百科 来源:网络整理
导读:我从Appledoc那里读到了关于着名(或臭名昭着的?)init方法的内容 In some cases,an init method might return a substitute object. You must therefore always use the object returned by init,and not the one returned by alloc or allocWithZone:,in su
我从Appledoc那里读到了关于着名(或臭名昭着的?)init方法的内容

In some cases,an init method might return a substitute object. You must therefore always use the object returned by init,and not the one returned by alloc or allocWithZone:,in subsequent code.

所以说我有这两个班

@interface A : NSObject
@end

@interface B : A
@property (nonatomic,strong) NSArray *usefulArray;
@end

具有以下实现

@implementation A
+(NSMutableArray *)wonderfulCache {
    static NSMutableArray  *array = nil;
    if (!array)
        array = [NSMutableArray array];
    return array;
}

-(id)init {
    if (self=[super init]) {
        // substituting self with another object
        // A has thought of an intelligent way of recycling
        // its own objects
        if ([self.class wonderfulCache].count) {
            self = [self.class wonderfulCache].lastObject;
            [[self.class wonderfulCache] removeLastObject];
        } else {
            // go through some initiating process
            // ....
            if (self.canBeReused)
                [[self.class wonderfulCache] addObject:self];
        }
    }
    return self;
}

-(BOOL) canBeReused {
    // put in some condition 
    return YES;
}
@end

@implementation B
-(id)init {
    if (self=[super init]) {
        // setting the property
        self.usefulArray = [NSArray array];
    }
    return self;
}
@end

当B调用init时,[super init]可能会返回一个替换的A对象,当B尝试设置属性(A没有)时,它不会导致错误吗?

如果这确实导致错误,我们如何以正确的方式实现上述模式?

更新:附加更真实的特定问题

这是一个名为C的C类(其用法将在后面解释)

class C
{
    /// Get the user data pointer 
    void* GetUserData() const;

    /// Set the user data. Use this to store your application specific data.
    void SetUserData(void* data);
}

说A的目的是充当C的包装;并且始终在A和C之间保持一对一的关系至关重要.

所以我想出了以下的接口和实现

@interface A : NSObject
-(id)initWithC:(C *)c;
@end

@implementation A {
    C *_c;
}
-(id)initWithC:(C *)c {
    id cu = (__bridge id) c->GetUserData();
    if (cu) {
        // Bingo,we've got the object already!
        if ([cu isKindOfClass:self.class]) {
            return (self = cu);
        } else {
           // expensive operation to unbind cu from c
           // but how...?
        }
    } 
    if (self=[super init]) {
        _c = c;
        c->SetUserData((__bridge void *)self);
        // expensive operation to bind c to self
        // ...
    }
    return self;
}
@end

这暂时适用.现在我想把A分类,所以我想出了B.

@interface B : A
@property (nonatomic,strong) NSArray *usefulArray;
@end

现在出现问题,因为A不知道如何正确解除绑定实例.所以我必须修改上面的代码

@interface A : NSObject {
    C *_c;
}
-(id)initWithC:(C *)c;
-(void) bind;
-(void) unbind;
@end

@implementation A 
-(id)initWithC:(C *)c {
    id cu = (__bridge id) c->GetUserData();
    if (cu) {
        // Bingo,we've got the object already!
        if ([cu isKindOfClass:self.class]) {
            return (self = cu);
        } else {
            NSAssert([cu isKindOfClass:[A class]],@"inconsistent wrapper relationship");
           [(A *)cu unbind];
        }
    } 
    if (self=[super init]) {
        _c = c;
        c->SetUserData((__bridge void *)self);
        [self bind];
    }
    return self;
}

-(void) bind {
    //.. do something about _c
}

-(void) unbind {
    // .. do something about _c
    _c = nil;
}
@end

现在B只需要覆盖bind和unbind就能使它工作.

但是当我想到它时,所有B想要做的就是有一个额外的数组有用,它是否真的值得这么多工作……?编写unbind只是为了让你的子类以与C对象的1对1关系替换你的想法看起来很奇怪(而且效率也很低).

解决方法

似乎有一个误解:
init方法必须始终返回接收类类型的实例.
如果 – [A init]在[B init]中通过[super init]调用,则self为a
(已分配但尚未初始化)B类实例.因此 – [初始化]
必须返回B类(或子类)的实例.

因此,如果您决定“回收”对象,则必须确保该对象
正确的课程被回收.

我不知道在你的情况下“在init中替换self”是不是很糟糕的做法可能取决于对象和canBeReused条件.它主要是由“类集群”,如NSNumber,NSArray等.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读