2014-10-22 18 views
6

Tôi đang cố gắng chuyển một ứng dụng từ Objective-C sang Swift, nhưng tôi đang gặp sự cố với lớp con của GPUImageFilter.Chuyển các lớp con của bộ lọc GPUImage sang Swift

Trong obj-C, subclassing GPUImageFilter và sử dụng một Shader đoạn khác nhau là dễ dàng như

- (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; 
} 

tôi không thể tìm ra cách để làm điều này trong Swift. Đây là khởi tạo mới của tôi:

override init() { 
    let fragmentShaderPathname = NSBundle.mainBundle().pathForResource("TestShader", ofType: "fsh")! 
    let fragmentShaderString = NSString(contentsOfFile: fragmentShaderPathname, encoding: NSUTF8StringEncoding, error: nil) 

    super.init(fragmentShaderFromString: fragmentShaderString) 
} 

Ngay sau khi điều này được gọi, treo ứng dụng với thông báo lỗi này: /Users/peterwunder/Documents/XCode/welp/welp/GPUImageTestFilter.swift: 12: 7: fatal error: use of unimplemented initializer 'init(vertexShaderFromString:fragmentShaderFromString:)' for class 'welp.GPUImageTestFilter'

Tôi đang làm gì sai?

Trả lời

7

Vấn đề thú vị! Bạn đang bị vấp ngã do sự khác biệt trong khởi tạo giữa Swift và Objective-C. Nếu lớp GPUImageFilter được viết bằng Swift, trình biên dịch sẽ không cho phép bạn có thiết lập này, nhưng vì bạn đang trộn & khớp với nó, nó không phàn nàn cho đến khi chạy. Đây là những gì đang xảy ra khi bạn cố gắng để nhanh chóng phân lớp của bạn:

  1. Bạn gọi let myFilter = CustomGPUImageFilter()
  2. init() tải của bạn chuỗi shader và gọi super.init(fragmentShaderString: "foo")
  3. GPUImageFilter.init(fragmentShaderString:) cuộc gọi [self initWithVertexShaderFromString:@"bar" fragmentShaderFromString:@"foo"].

Loại nào là self trong dòng cuối cùng? Nếu bạn đang gọi từ trình khởi tạo của lớp con, loại self thực sự là của lớp con của bạn: CustomGPUImageFilter. Vì vậy, initializer được gọi là thực sự trên lớp con của bạn. Tại sao điều này là một vấn đề?

Thật không may, các lớp Swift không tự động kế thừa trình khởi tạo từ lớp cha của chúng nếu chúng xác định chỉ định trình khởi tạo của riêng mình, đó là số init() của bạn. Vì vậy, thời gian chạy cố gắng gọi CustomGPUImageFilter.init(vertexShaderFromString:fragmentShaderFromString:), không tìm thấy nó và gặp sự cố với thông báo lỗi đó.

Hạnh phúc, bản sửa lỗi khá đơn giản. Nếu bạn đánh dấu công cụ khởi tạo là convenience init, bạn sẽ không còn xác định trình khởi tạo được chỉ định, có nghĩa là lớp con của bạn sẽ kế thừa trình khởi tạo từ GPUImageFilter. Sau đó, ở bước 3 ở trên, thời gian chạy sẽ tìm thấy trình khởi tạo kế thừa trên lớp con của bạn và thực thi mà không có sự cố. Lưu ý rằng bạn sẽ cần phải gọi self.init... thay vì 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) 
} 

Để biết thêm về quá trình này, hãy đọc phần trên class inheritance and initialization trong tài liệu Swift. Quá trình này là đáng kể khác với Mục tiêu-C.

+1

Dang. Tôi mong rằng mọi thứ về cơ bản sẽ khác nhau, nhưng tôi không ngờ là _this_. : D Cảm ơn! –

Các vấn đề liên quan