防止在 iOS 中分配类

Posted

技术标签:

【中文标题】防止在 iOS 中分配类【英文标题】:Prevent class from being allocated in iOS 【发布时间】:2013-08-22 20:18:16 【问题描述】:

我想知道如何在 Objective-C 中创建一个无法分配(或初始化)的类?

我正在尝试复制 SKDownload Apple 类(StoreKit 框架),我注意到文档没有提及任何 alloc 或 init 方法。 这可能在文档中丢失但出现在代码中? (缺少一些 .h 声明以阻止我们使用此方法?)。我试过 +alloc-init 这个类,alloc 和 init 都返回 null。

我想要实现的是一个只有 getter 的 B 类,它只能由 A 类创建(就像工厂方法一样 - 只有 A 可以创建和返回 B 实例,但用户不能创建B 直接)。

例子:

@interface A : NSObject
// Only A "+createB" class method can create B instances
+ (Second *)createBWithValue:(int)value;
@end

@interface B : NSObject
- (id)init; // return nil
+ (id)alloc; // return nil
- (int)value; // this returns the value passed from A
@end

问题 1:您将如何着手创建此类课程?有可能吗?

问题2: B上的-(int)value如何返回A中类方法传入的值? (知道 +alloc、-init 和/或其他内存分配方法可能无效,因为用户无法直接创建 B 类 - B 中的自定义 initWithValue 方法也可能不可用)

我对 Apple 工程师如何做到这一点感到有些困惑……是否存在 Apple 不希望我使用的隐藏方法?

谢谢。

【问题讨论】:

@implementation Foo +(id) alloc return nil; @end 旁注:SKDownload 确实allocinit 方法——Apple 的类文档只排除了继承的方法。 是的,文档中缺少 alloc/init 并不表示不应使用这些。 Apple 文档几乎总是忽略没有新语义的继承方法。例如,NSDateFormatter 没有列出 alloc 或 init,但您当然必须使用它们才能使用该类。 @Nicolas:不一定。有一个不同的指定初始化程序 (initWithXPCEncoding:),如下所示:gist.github.com/mdippery/49eb8e548784982c668f 但同样,还有一个 allocinit 方法可以执行您所期望的操作(即返回类的实例) . @Nicolas:nm 工具:developer.apple.com/library/mac/documentation/Darwin/Reference/… 【参考方案1】:

我注意到文档没有提到任何 alloc 或 init 方法

来自文档:

您的应用从不直接创建 SKDownload 对象。相反,在处理完付款后,您的应用程序会读取交易对象的 downloads 属性以检索 SKDownload 对象数组 与交易相关联。

是否存在 Apple 不希望我使用的隐藏方法?

是的。有很多 Apple 不希望你使用的隐藏方法。

因此,您不应该自己创建SKDownload 的实例,因此初始化方法不是公共API 的一部分。这并不意味着无法创建 SKDownload 实例,只是没有公开的方式来创建它们。

类限制分配或初始化是很常见的。例如,单例类通常会覆盖+allocWithZone:,这样它只会在尚未创建新对象时分配一个新对象;如果存在,则返回该对象(初始化程序基本上什么都不做)。

隐藏初始化器。

如果您想自己创建这样的类,请覆盖继承的初始化方法(可能只是 -init),以便它们返回 nil 或者甚至抛出异常。实现您自己的初始化程序,但不要将其置于类的公共接口之外:

// B.h
@interface B : NSObject
@property(readonly) int value;
@end;

// B.m
@interface B ()
@property(readwrite) int value;
-(id)secretInitializerWithValue:(int)v;
@end

@implementation B
-(id)secretInitializerWithValue:(int)v

    if ((self == [super init]))    // not really necessary since NSObject's -init doesn't do anything
        _value = v;
    


-(id)init

     @throw [NSException exceptionWithName:@"Don't do that!" 
                                    reason:@"You shouldn't instantiate B yourself."
                                  userInfo:nil];

@end

私有可变子类。

另一种选择是创建一个具有所需只读访问器的不可变类,以及一个具有读写访问器的私有可变子类。您可以在可变子类中实现-copyWithZone:,以便在复制时获得不可变对象。这一切都与我在上面描述的差不多——无论哪种方式,您都在向客户端隐藏创建机制。

【讨论】:

认为这不是在回答 OP 的问题。他不是在问如何alloc-init 一个SKDownload 实例。他想模仿那个类的行为(即alloc-init返回nil,只有所有者和上帝知道如何实例化它。) 是的,我明白了。这就是我想要复制的。我不希望我的框架用户能够实例化一些 B 类,但我希望他们能够使用 B 类实例(我可以通过类方法返回我的用户)。 @Nicolas 我只告诉过你在过去 20 分钟左右 两次 >.不覆盖alloc以返回nil。 2. 即使是这样,class_createInstance() 仍然有效。 @Nicolas 可以,但我不会更改+alloc。大多数情况下,仅隐藏初始化程序就足够了。 @Nicolas:苹果隐藏初始化机制。您仍然可以调用 [[SKDownload alloc] init],但根据 API,您不应该,因为这些方法不会做任何有趣或有用的事情。

以上是关于防止在 iOS 中分配类的主要内容,如果未能解决你的问题,请参考以下文章

如何在 swift 4 的闭包中分配类属性

如何在 C++ 中分配类内数组的可修改大小

如何在 TestNG 单元测试类中分配类级别数据

C ++从不同的函数中分配类成员的值

如何防止声明为局部变量的对象在堆栈中分配?

是否可以防止zend引擎释放资源?