2016-03-23 20 views
9
protocol LazyUpdateable { 
    func waitToDoStuff() 
    func myMethodName() 
} 


extension LazyUpdateable where Self: NSObject { 
    func waitToDoStuff() { 
     self.performSelector(#selector(myMethodName), withObject: nil, afterDelay: 1.5) 
    } 

    func myMethodName() { 

    } 
} 

Với bản cập nhật này, tôi gặp lỗi Argument of #selector refers to a method that is not exposed to objective c, nhưng nếu tôi đi với cũ Selector("myMethodName") tôi nhận được cảnh báo để thay đổi cách làm tốt hơn. Có thể sử dụng số #selector() trong trường hợp này không? Nó sẽ không hoạt động với thiết lập @objc trên giao thức của tôi, tôi đã thử nó.Làm thế nào để sử dụng #selector (myMethodName) trong một phần mở rộng giao thức?

Đây là một sân chơi bạn có thể thử cho thấy nó không hoạt động với thiết @objc

import Foundation 
import UIKit 
import XCPlayground 


@objc protocol LazyUpdatable { 
    optional func waitToDoStuff() 
    optional func myMethodName() 
} 

extension LazyUpdatable where Self: UIViewController { 
    func waitToDoStuff() { 
     self.performSelector(#selector(myMethodName), withObject: nil, afterDelay: 1.5) 
    } 

    func myMethodName() { 
     print("LOL") 
    } 
} 


@objc 
class AViewController: UIViewController, LazyUpdatable { 
    func start() { 
     waitToDoStuff() 
    } 
} 

let aViewController = AViewController() 
aViewController.start() 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

Trả lời

3

động điều phối sử dụng #selector() hoặc Selector() không thấy phần mở rộng giao thức Swift của bạn. Thay vào đó, hãy thử tránh Objective-C hoàn toàn, nếu có thể. Bạn có thể đạt được kết quả tương tự bằng cách sử dụng libdispatch:

protocol LazyUpdatable { 

    func waitToDoStuff() 
    func myMethodName() 
} 

extension LazyUpdatable { 

    func waitToDoStuff() { 
     let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.5 * Double(NSEC_PER_SEC))) 
     dispatch_after(dispatchTime, dispatch_get_main_queue()) { 
      self.myMethodName() 
     } 
    } 

    func myMethodName() { 
     print("Aloha!") 
    } 
} 

class ViewController: UIViewController, LazyUpdatable { 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     waitToDoStuff() 
    } 
} 

Được cấp, điều này không linh hoạt như sử dụng bộ chọn, nhưng cho phép bạn sử dụng tiện ích mở rộng giao thức Swift thực.

EDIT: Nếu bạn muốn để có thể hủy bỏ cách gọi các cuộc gọi phương thức, hãy thử như sau:

var lazyUpdatableCancelKey = UInt8(0) 

protocol LazyUpdatable: class { 

    func waitToDoStuff() 
    func cancelDoingStuff() 
    func myMethodName() 
} 

extension LazyUpdatable { 

    func waitToDoStuff() { 
     let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.5 * Double(NSEC_PER_SEC))) 
     dispatch_after(dispatchTime, dispatch_get_main_queue()) { 
      if let shouldCancel = objc_getAssociatedObject(self, &lazyUpdatableCancelKey) as? Bool where shouldCancel == true { 
       return 
      } 
      self.myMethodName() 
     } 
    } 

    func cancelDoingStuff() { 
     objc_setAssociatedObject(self, &lazyUpdatableCancelKey, true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) 
    } 

    func myMethodName() { 
     print("Aloha!") 
    } 
} 

class ViewController: UIViewController, LazyUpdatable { 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     waitToDoStuff() 

     let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1.4 * Double(NSEC_PER_SEC))) 
     dispatch_after(dispatchTime, dispatch_get_main_queue()) { 
      self.cancelDoingStuff() 
     } 
    } 
} 
1

Đối với XCode 8.2.1 và Swift 3.

Bạn có thể sử dụng số Selector("methodName") truyền thống như bạn đã thử. Ngoài ra, bạn có thể tắt tiếng cảnh báo bằng cách gói cảnh báo đó vào dấu ngoặc đơn Selector(("methodName"))

Vì mọi thứ nằm trong giao thức của bạn, ít có khả năng bạn sẽ mắc lỗi chính tả sẽ bị lỗi

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