2016-02-04 4 views
2

Я столкнулся с этой проблемой, которую я не смог решить и не нашел много об этом.Возвращаемый объект конкретного класса, который реализует протокол

Мое дело в том, что с фабричной функции я хочу вернуть экземпляр UIViewController, который также реализует протокол, назовем его Protocol. Я хотел бы знать, кто-нибудь испытал это и нашел какое-либо решение?

В Objective-C это будет выглядеть следующим образом:

- (UIViewController<Protocol>*)createControllerForIdentifier:(NSString*)identifier 

Есть ли Swift способ написать это?

Ограничение Protocol к конкретному классу или подклассу было бы в порядке для моего случая.

Я нашел this thread, но не был в состоянии преобразовать в моем случае

Спасибо за вашу помощь.

ответ

1

Swift 4 ❤️

func createController(for identifier: String) -> (UIViewController & Protocol)

0

Один из способов заключается в следующем:

protocol Protocol { 
    func bar() 
} 

class MyViewController : UIViewController, Protocol { 

    func bar() { 
     print("Bar") 
    } 

    static func getInstance() -> MyViewController { 
     return self.init() 
    } 

} 

/* Example usage */ 
let foo = MyViewController.getInstance() 
print(foo.dynamicType) // MyViewController 
foo.bar() // Bar 

/* Naturally works to pass foo to 'Protocol' type constrained function */ 
func foobar<T: Protocol>(fizz: T) { 
    fizz.bar() 
} 
foobar(foo) // bar 

Или, для более общего/Многоразовый подхода (фабричный метод для классов/структур, которые имеют простой init() инициализатору доступный):

/* Setup generic factory */ 
protocol FactoryInitializers { 
    init() 
} 

protocol FactoryMethods { 
    typealias T: FactoryInitializers 
} 
extension FactoryMethods { 
    static func getInstance() -> T { 
     return T() 
    } 
} 

protocol Factory : FactoryMethods, FactoryInitializers { } 

/* Apply for your example, with conformance to 'Factory' (to get access 
    to default implementation 'getInstance' method) as well as a custom 
    protocol 'Protocol'    */ 
protocol Protocol { 
    func bar() 
} 

class MyViewController : UIViewController, Factory, Protocol { 
    typealias T = MyViewController 

    func bar() { 
     print("Bar") 
    } 
} 

с таким же результатом, как более простой версии выше:

let foo = MyViewController.getInstance() // OK, MyViewController conforms to Factory 
print(foo.dynamicType) // MyViewController 
foo.bar() // Bar 

/* Naturally works to pass foo to 'Protocol' type constrained function */ 
func foobar<T: Protocol>(fizz: T) { 
    fizz.bar() 
} 
foobar(foo) // bar 
1

Существует несколько вариантов в зависимости от специфики. Вот один общий подход, который может помочь. Тем не менее, я рекомендую переписать код, так что это не проблема. Swift и Objective-C - это разные языки, и некоторые шаблоны проектирования просто не доступны (и никогда не будут) доступны для обоих языков. В таких случаях код переноса требует переосмысления кода с нуля.

Вы можете достичь безопасности и удобства пути введения обязательного протокола следующим образом:

// protocol you want to implement 
// this may possibly be implemented by other types besides our Base (no restrictions) 
protocol P1 { 
    func run() 
} 


// base class of objects to instantiate 
class Base { 
    // Base specific method 
    func display() { 
     print("Displaying...") 
    } 
} 


// wrapper to get both P1 and Base 
// our special protocol will be dedicated to P1 and Base 
protocol PB : P1 {  // already a P1 
    // property to safely get this instance as a Base without casting 
    var asBase : Base { get } 
} 


// extension to safely implement the binding for P1 and Base 
// anything we implement in this extension is safe for both P1 and Base 
extension PB where Self : Base { 
    var asBase : Base { return self } 
} 


// concrete subclass of Base which also implements PB and hence P1 
class X : Base, PB { 
    // implement protocol 
    func run() { 
     print("Running...") 
    } 
} 


// factory function to make a concrete instance of Base implementing P1 
func makePB() -> PB { 
    return X() 
} 


let pb = makePB() 
pb.run()    // directly access as P1 
pb.asBase.display()  // both safe and easy to access as Base 
Смежные вопросы