I am deep in the woods converting an existing Objective-C app to Swift. This post shows how to convert an Objective-C protocol that returns an object conforming to a protocol to Swift. Pay special attention to the typealias
used in the ModalViewControllerProvider
(that's the key to whole thing).
Objective-C Protocol That Returns An Object Conforming To A Protocol
The app makes use of a protocol named HRLModalViewControllerProvider
to "provide" a view controller at runtime bound to a given object.
@protocol HRLModalViewControllerProvider<NSObject>
- (UIViewController<HRLModalPresentationCompletion> *)viewControllerWithObject:(id)object;
@end
The returned view controller must conform to the HRLModalPresentationCompletion
in order for the view controller to be modally presented and appropriately dismissed.
@protocol HRLModalPresentationCompletion<NSObject>
@property (nonatomic, copy, readwrite) void(^completionBlock)(BOOL changed);
@end
Swift Conversion
Let's start with converting the HRLModalPresentationCompletion
protocol to a Swift protocol.
protocol ModalPresentationCompletion {
var completion: ((changed: Bool) -> Void)? { get set }
}
That protocol converts pretty easily from Objective-C to Swift. Here's how to convert the HRLModalViewControllerProvider
Objective-C protocol to a Swift protocol.
protocol ModalViewControllerProvider {
typealias V: UIViewController, ModalPresentationCompletion
func viewControllerWithObject(object: AnyObject) -> V
}
The trick is setting up a typealias
. Here's how to read the typealias
. > V
"is a" UIViewController
that conforms to the ModalPresentationCompletion
protocol
Perfect! Simply type the method's return value as V
.
Bonus Conversion
Let's improve the protocol by "generifying" the method's parameter.
protocol ModalViewControllerProvider {
typealias T: AnyObject
typealias V: UIViewController, ModalPresentationCompletion
func viewControllerWithObject(object: T) -> V
}
Even better!
Sample Implementation
public override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let object = self.myDataController.objectAtIndexPath(indexPath)
var viewController = self.viewControllerProvider.viewControllerWithObject(object)
viewController.completion = { (changed: Bool) in
self.dismissViewControllerAnimated(true, completion: nil)
}
let navigationController = UINavigationController(rootViewController: viewController)
self.presentViewController(navigationController, animated: true, completion: nil)
}
And here's an example ModalViewControllerProvider
implementation:
class SensorTrackViewControllerProvider: ModalViewControllerProvider {
func viewControllerWithObject(object: SensorTrack) -> SensorTrackViewController {
return SensorTrackViewController(object) // assume conforms to ModalPresentationCompletion
}
}
Summary
The conversion turns out to be pretty simple. Just remember that typealias
is the key to solving the problem.
On to the next feature.