我正在尝试将应用程序从Objective-C移植到Swift,但我遇到了GPUImageFilter子类的问题。
在Obj-C中,继承GPUImageFilter并使用不同的片段着色器就像
一样简单- (id)init;
{
NSString *fragmentShaderPathname = [[NSBundle mainBundle] pathForResource:@"TestShader" ofType:@"fsh"];
NSString *fragmentShaderString = [NSString stringWithContentsOfFile:fragmentShaderPathname encoding:NSUTF8StringEncoding error:nil];
if (!(self = [super initWithFragmentShaderFromString:fragmentShaderString]))
{
return nil;
}
return self;
}
我无法弄清楚如何在Swift中执行此操作。这是我的新初始化程序:
override init() {
let fragmentShaderPathname = NSBundle.mainBundle().pathForResource("TestShader", ofType: "fsh")!
let fragmentShaderString = NSString(contentsOfFile: fragmentShaderPathname, encoding: NSUTF8StringEncoding, error: nil)
super.init(fragmentShaderFromString: fragmentShaderString)
}
一旦调用此应用程序,应用程序就会崩溃并显示以下错误消息:
/Users/peterwunder/Documents/XCode/welp/welp/GPUImageTestFilter.swift: 12: 7: fatal error: use of unimplemented initializer 'init(vertexShaderFromString:fragmentShaderFromString:)' for class 'welp.GPUImageTestFilter'
我做错了什么?
答案 0 :(得分:7)
有趣的问题!由于Swift和Objective-C之间的初始化不同,您将被绊倒。如果GPUImageFilter
类是用Swift编写的,那么编译器就不会让你进行这种设置,但是因为你正在混合使用它。匹配它直到运行时才会抱怨。以下是您尝试实例化子类时发生的情况:
let myFilter = CustomGPUImageFilter()
init()
加载着色器字符串并调用super.init(fragmentShaderString: "foo")
GPUImageFilter.init(fragmentShaderString:)
来电[self initWithVertexShaderFromString:@"bar" fragmentShaderFromString:@"foo"]
。最后一行中self
的类型是什么?如果您从子类的初始化程序调用,self
的类型实际上是您的子类的类型:CustomGPUImageFilter
。因此被调用的初始化程序实际上在您的子类上。为什么这是一个问题?
不幸的是,如果Swift类定义了自己的指定的初始值设定项,那么它们就不会自动从其超类继承初始化器,这就是你的init()
。因此运行时尝试调用CustomGPUImageFilter.init(vertexShaderFromString:fragmentShaderFromString:)
,找不到它,并且崩溃并显示该错误消息。
令人高兴的是,修复非常简单。如果您将初始化程序标记为convenience init
,则不再定义指定的初始值设定项,这意味着您的子类将继承GPUImageFilter
的初始值设定项。然后在上面的步骤3中,运行时将在子类上找到继承的初始化程序并执行而不会出现问题。请注意,您需要拨打self.init...
而不是super.init...
:
convenience override init() {
let fragmentShaderPathname = NSBundle.mainBundle().pathForResource("TestShader", ofType: "fsh")!
let fragmentShaderString = NSString(contentsOfFile: fragmentShaderPathname, encoding: NSUTF8StringEncoding, error: nil)
self.init(fragmentShaderFromString: fragmentShaderString)
}
有关此过程的更多信息,请阅读Swift文档中有关class inheritance and initialization的部分。该过程显着与Objective-C不同。