[英]Porting GPUImage filter subclasses to Swift
I'm trying to port an app from Objective-C to Swift, but I'm having problems with a subclass of GPUImageFilter. 我正在尝试将应用程序从Objective-C移植到Swift,但我遇到了GPUImageFilter子类的问题。
In Obj-C, subclassing GPUImageFilter and using a different fragment shader was as easy as 在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;
}
I can't figure out how to do this in Swift. 我无法弄清楚如何在Swift中做到这一点。 This is my new initializer:
这是我的新初始化程序:
override init() {
let fragmentShaderPathname = NSBundle.mainBundle().pathForResource("TestShader", ofType: "fsh")!
let fragmentShaderString = NSString(contentsOfFile: fragmentShaderPathname, encoding: NSUTF8StringEncoding, error: nil)
super.init(fragmentShaderFromString: fragmentShaderString)
}
As soon as this gets called, the app crashes with this error message: /Users/peterwunder/Documents/XCode/welp/welp/GPUImageTestFilter.swift: 12: 7: fatal error: use of unimplemented initializer 'init(vertexShaderFromString:fragmentShaderFromString:)' for class 'welp.GPUImageTestFilter'
一旦调用此应用程序,应用程序就会崩溃并显示以下错误消息:
/Users/peterwunder/Documents/XCode/welp/welp/GPUImageTestFilter.swift: 12: 7: fatal error: use of unimplemented initializer 'init(vertexShaderFromString:fragmentShaderFromString:)' for class 'welp.GPUImageTestFilter'
What am I doing wrong? 我究竟做错了什么?
Interesting problem! 有趣的问题! You're getting tripped up due to the differences in initialization between Swift and Objective-C.
由于Swift和Objective-C之间的初始化不同,您将被绊倒。 If the
GPUImageFilter
class were written in Swift, the compiler wouldn't let you have this setup, but since you're mixing & matching it doesn't complain until runtime. 如果
GPUImageFilter
类是用Swift编写的,那么编译器就不会让你进行这种设置,但是由于你GPUImageFilter
混合和匹配,所以直到运行时它才会出现问题。 Here's what's happening when you try to instantiate your subclass: 以下是您尝试实例化子类时发生的情况:
let myFilter = CustomGPUImageFilter()
let myFilter = CustomGPUImageFilter()
init()
loads the shader string and calls super.init(fragmentShaderString: "foo")
init()
加载着色器字符串并调用super.init(fragmentShaderString: "foo")
GPUImageFilter.init(fragmentShaderString:)
calls [self initWithVertexShaderFromString:@"bar" fragmentShaderFromString:@"foo"]
. GPUImageFilter.init(fragmentShaderString:)
调用[self initWithVertexShaderFromString:@"bar" fragmentShaderFromString:@"foo"]
。 What type is self
in that last line? 最后一行是什么类型的
self
? If you're calling from your subclass's initializer, the type of self
is actually that of your subclass: CustomGPUImageFilter
. 如果您从子类的初始化程序调用,则
self
的类型实际上是您的子类的类型: CustomGPUImageFilter
。 So the initializer that gets called is actually on your subclass. 因此被调用的初始化程序实际上在您的子类上。 Why is this a problem?
为什么这是个问题?
Unfortunately, Swift classes don't automatically inherit the initializers from their superclass if they define their own designated initializers, which is what your init()
is. 不幸的是,如果Swift类定义了自己的指定初始值设定项,那么它们就不会自动从超类继承初始化器,这就是你的
init()
。 So the runtime tries to call CustomGPUImageFilter.init(vertexShaderFromString:fragmentShaderFromString:)
, doesn't find it, and crashes with that error message. 因此,运行时尝试调用
CustomGPUImageFilter.init(vertexShaderFromString:fragmentShaderFromString:)
,找不到它,并与该错误消息崩溃。
Happily, the fix is quite simple. 令人高兴的是,修复非常简单。 If you mark your initializer as
convenience init
, you'll no longer be defining a designated initializer, which means your subclass will inherit the initializers from GPUImageFilter
. 如果您标记您的初始化为
convenience init
,您将不再被定义指定初始化,这意味着你的子类将继承初始化GPUImageFilter
。 Then in step 3 above, the runtime will find the inherited initializer on your subclass and execute without a problem. 然后在上面的步骤3中,运行时将在子类上找到继承的初始化程序并执行而不会出现问题。 Note that you'll need to call
self.init...
instead of super.init...
: 请注意,您需要调用
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)
}
For more about this process, read the section on class inheritance and initialization in the Swift documentation. 有关此过程的更多信息,请阅读Swift文档中有关类继承和初始化的部分。 The process is significantly different from Objective-C.
该过程与Objective-C有很大不同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.