简体   繁体   中英

Class and Protocol Inheritance in Swift

Let's say I have a protocol in Swift

protocol SearchCompletionProtocol {
    func searchSuccessful(results: [AnyObject])
    func searchCancelled()
}

Now let's say that I have a class and in the init method I want to pass in a single argument. The restriction is that I want this argument to be of type UIViewController and also conform to the SearchCompletionProtocol protocol. How would I go about doing that? Here are some examples of things I've tried and they all don't work.

class SearchDelegate: UISearchDisplayController, UISearchBarDelegate {

    let completionDelegate: SearchCompletionProtocol

    init<T: SearchCompletionProtocol where T: UIViewController>(completionDelegate: T) {
        self.completionDelegate = completionDelegate
        let _searchBar = UISearchBar()
        super.init(searchBar: _searchBar, contentsController: completionDelegate)
    }
}

I've also tried restricting inheritance on the protocol to only classes of type UIViewController, but that also does not work.

protocol SearchCompletionProtocol: class, UIViewController {
    func searchSuccessful(results: [AnyObject])
    func searchCancelled()
}

Of course I could easily just pass in two arguments to this method, one conforming to the search protocol and one being of type UIViewController, but that just seems not very Swifty.

So it looks like the solution to this was me stripping out my original code thinking it wasn't important. Here was my original code

protocol SearchCompletionProtocol {
    func searchSuccessful(results: [RTruck])
    func searchCancelled()
}

class SearchDelegate: UISearchDisplayController, UISearchBarDelegate {
    let completionDelegate: SearchCompletionProtocol

    init<T: SearchCompletionProtocol where T: UIViewController>(completionDelegate: T) {
        self.completionDelegate = completionDelegate
        let _searchBar = UISearchBar()
        super.init(searchBar: _searchBar, contentsController: completionDelegate)
        self.completionDelegate.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
    }
}

The issue here is that I used self.completionDelegate.navigationItem . The type of the class level completionDelegate is just the SearchCompletionProtocol and it is not of type T. removing the self caused it to use the passed in argument which was guaranteed to be a UIViewController in the eyes of the compiler and everything worked just fine. Here's the working code

protocol SearchCompletionProtocol {
    func searchSuccessful(results: [RTruck])
    func searchCancelled()
}

class SearchDelegate: UISearchDisplayController, UISearchBarDelegate {
    let completionDelegate: SearchCompletionProtocol

    init<T: SearchCompletionProtocol where T: UIViewController>(completionDelegate: T) {
        self.completionDelegate = completionDelegate
        let _searchBar = UISearchBar()
        super.init(searchBar: _searchBar, contentsController: completionDelegate)
        completionDelegate.navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "showSearchBar")
    }
}

In Swift 4 you can achieve this with the new & sign:

func foo(vc: UIViewController & SearchCompletionProtocol) {
    vc.searchCancelled()
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM