在Swift运行时创建Objective-Cclass对象,符合Objective-C协议
Create object of Objective-C class at runtime in Swift, which conforms to Objective-C protocol
我有 Objective-C 协议和接口实现如下:
@protocol Animal <NSObject>
-(void)walk;
@end
@interface Cat : NSObject<Animal>
@end
@implementation Cat
-(void)walk{}
@end
@interface Dog : NSObject<Animal>
@end
@implementation Dog
-(void)walk{}
@end
我正在尝试在运行时使用 类 的实例来实现协议 'Animal'。此代码在 swift 中:
var classesCount = objc_getClassList(nil, 0)
let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(classesCount))
classesCount = objc_getClassList(AutoreleasingUnsafeMutablePointer(allClasses), classesCount)
for i in 0..<classesCount{
let cls : AnyClass! = allClasses[Int(i)]
if class_conformsToProtocol(cls, Animal.self){
let instance = cls.self.init()
instance.walk()
}
}
尝试了很多方法从 AnyClass、AnyObject 和 NSObject 获取实例。我这样做时遇到编译器错误。此代码段的错误是:
'required' initializer 'init(arrayLiteral:)' must be provided by subclass of 'NSSet'.
有什么方法可以获取 'Cat' 和 'Dog' 的实例吗?
让我们在 Animal
上定义一个 noise
方法用于测试:
@protocol Animal <NSObject>
- (NSString *)noise;
@end
此外,让我们使用一个普通的 Swift 数组来保存 class 列表:
let allClassesCount = objc_getClassList(nil, 0)
var allClasses = [AnyClass](repeating: NSObject.self, count: Int(allClassesCount))
allClasses.withUnsafeMutableBufferPointer { buffer in
let autoreleasingPointer = AutoreleasingUnsafeMutablePointer<AnyClass>(buffer.baseAddress)
objc_getClassList(autoreleasingPointer, allClassesCount)
}
然后,当我们找到一个符合Animal
的class,我们把它转换成合适的Swift类型((NSObject & Animal).Type
),这样当我们实例化它的时候, 我们得到一个适当类型的对象 (NSObject & Animal
):
for aClass in allClasses {
if class_conformsToProtocol(aClass, Animal.self) {
let animalClass = aClass as! (NSObject & Animal).Type
// Because animalClass is `(NSObject & Animal).Type`:
// - It has the `init()` of `NSObject`.
// - Its instances are `NSObject & Animal`.
let animal = animalClass.init()
// Because animal is `NSObject & Animal`, it has the `noise` method of `Animal`.
print(animal.noise())
}
}
输出:
woof
meow
旁注。您可能认为这样做可以避免使用 class_conformsToProtocol
:
if let animalClass = aClass as? (NSObject & Animal).Type {
let animal = animalClass.init()
print(animal.noise())
}
但是你会在运行时崩溃:
*** CNZombie 3443: -[ conformsToProtocol:] sent to deallocated instance 0x7fffa9d265f0
在幕后,as?
测试使用正常的 Objective-C 消息发送 conformsToProtocol:
消息到 aClass
。但是系统框架中有各种“僵尸classes”,当任何消息发送给它们时崩溃。这些 classes 用于检测释放后使用错误。 class_conformsToProtocol
函数不使用 Objective-C 消息传递,因此它避免了这些崩溃。
我有 Objective-C 协议和接口实现如下:
@protocol Animal <NSObject>
-(void)walk;
@end
@interface Cat : NSObject<Animal>
@end
@implementation Cat
-(void)walk{}
@end
@interface Dog : NSObject<Animal>
@end
@implementation Dog
-(void)walk{}
@end
我正在尝试在运行时使用 类 的实例来实现协议 'Animal'。此代码在 swift 中:
var classesCount = objc_getClassList(nil, 0)
let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(classesCount))
classesCount = objc_getClassList(AutoreleasingUnsafeMutablePointer(allClasses), classesCount)
for i in 0..<classesCount{
let cls : AnyClass! = allClasses[Int(i)]
if class_conformsToProtocol(cls, Animal.self){
let instance = cls.self.init()
instance.walk()
}
}
尝试了很多方法从 AnyClass、AnyObject 和 NSObject 获取实例。我这样做时遇到编译器错误。此代码段的错误是:
'required' initializer 'init(arrayLiteral:)' must be provided by subclass of 'NSSet'.
有什么方法可以获取 'Cat' 和 'Dog' 的实例吗?
让我们在 Animal
上定义一个 noise
方法用于测试:
@protocol Animal <NSObject>
- (NSString *)noise;
@end
此外,让我们使用一个普通的 Swift 数组来保存 class 列表:
let allClassesCount = objc_getClassList(nil, 0)
var allClasses = [AnyClass](repeating: NSObject.self, count: Int(allClassesCount))
allClasses.withUnsafeMutableBufferPointer { buffer in
let autoreleasingPointer = AutoreleasingUnsafeMutablePointer<AnyClass>(buffer.baseAddress)
objc_getClassList(autoreleasingPointer, allClassesCount)
}
然后,当我们找到一个符合Animal
的class,我们把它转换成合适的Swift类型((NSObject & Animal).Type
),这样当我们实例化它的时候, 我们得到一个适当类型的对象 (NSObject & Animal
):
for aClass in allClasses {
if class_conformsToProtocol(aClass, Animal.self) {
let animalClass = aClass as! (NSObject & Animal).Type
// Because animalClass is `(NSObject & Animal).Type`:
// - It has the `init()` of `NSObject`.
// - Its instances are `NSObject & Animal`.
let animal = animalClass.init()
// Because animal is `NSObject & Animal`, it has the `noise` method of `Animal`.
print(animal.noise())
}
}
输出:
woof
meow
旁注。您可能认为这样做可以避免使用 class_conformsToProtocol
:
if let animalClass = aClass as? (NSObject & Animal).Type {
let animal = animalClass.init()
print(animal.noise())
}
但是你会在运行时崩溃:
*** CNZombie 3443: -[ conformsToProtocol:] sent to deallocated instance 0x7fffa9d265f0
在幕后,as?
测试使用正常的 Objective-C 消息发送 conformsToProtocol:
消息到 aClass
。但是系统框架中有各种“僵尸classes”,当任何消息发送给它们时崩溃。这些 classes 用于检测释放后使用错误。 class_conformsToProtocol
函数不使用 Objective-C 消息传递,因此它避免了这些崩溃。