面向协议的程序设计可以用作Swift的核心设计模式。
不同类型可以遵循相同的协议,值类型甚至可以遵循多种协议,甚至可以提供默认的方法实现。
最初定义的协议可以表示特定类型或通用类型的常用属性和/或方法。
protocol ItemData { var title: String { get } var description: String { get } var thumbnailURL: NSURL { get } var created: NSDate { get } var updated: NSDate { get } } protocol DisplayItem { func hasBeenUpdated() -> Bool func getFormattedTitle() -> String func getFormattedDescription() -> String } protocol GetAPIItemDataOperation { static func get(url: NSURL, completed: ([ItemData]) -> Void) }
可以创建get方法的默认实现,但是如果需要的符合类型可能会覆盖该实现。
extension GetAPIItemDataOperation { static func get(url: NSURL, completed: ([ItemData]) -> Void) { let date = NSDate( timeIntervalSinceNow: NSDate().timeIntervalSince1970 + 5000) // 从网址获取数据 let urlData: [String: AnyObject] = [ "title": "Red Camaro", "desc": "一辆快速的红色汽车。", "thumb":"http://cars.images.com/red-camaro.png", "created": NSDate(), "updated": date] // 在此示例中,使用了强制展开 // 不得在实践中使用强制展开 // 而是应使用条件展开(警卫或if / let) let item = Item( title: urlData["title"] as! String, description: urlData["desc"] as! String, thumbnailURL: NSURL(string: urlData["thumb"] as! String)!, created: urlData["created"] as! NSDate, updated: urlData["updated"] as! NSDate) completed([item]) } } struct ItemOperation: GetAPIItemDataOperation { }
符合ItemData协议的值类型,此值类型也可以符合其他协议。
struct Item: ItemData { let title: String let description: String let thumbnailURL: NSURL let created: NSDate let updated: NSDate }
在这里,项目结构被扩展为符合显示项目。
extension Item: DisplayItem { func hasBeenUpdated() -> Bool { return updated.timeIntervalSince1970 > created.timeIntervalSince1970 } func getFormattedTitle() -> String { return title.stringByTrimmingCharactersInSet( .whitespaceAndNewlineCharacterSet()) } func getFormattedDescription() -> String { return description.stringByTrimmingCharactersInSet( .whitespaceAndNewlineCharacterSet()) } }
使用静态get方法的示例调用站点。
ItemOperation.get(NSURL()) { (itemData) in // 也许告知新数据视图 // 或解析数据以获取用户请求的信息等。 dispatch_async(dispatch_get_main_queue(), { //self.items = itemData }) }
不同的用例将需要不同的实现。这里的主要思想是展示各种类型的一致性,其中协议是设计重点。在此示例中,API数据可能有条件地保存到核心数据实体。
// 默认核心数据创建的类+扩展名 class LocalItem: NSManagedObject { } extension LocalItem { @NSManaged var title: String @NSManaged var itemDescription: String @NSManaged var thumbnailURLStr: String @NSManaged var createdAt: NSDate @NSManaged var updatedAt: NSDate }
在这里,核心数据支持的类也可以符合DisplayItem协议。
extension LocalItem: DisplayItem { func hasBeenUpdated() -> Bool { return updatedAt.timeIntervalSince1970 > createdAt.timeIntervalSince1970 } func getFormattedTitle() -> String { return title.stringByTrimmingCharactersInSet( .whitespaceAndNewlineCharacterSet()) } func getFormattedDescription() -> String { return itemDescription.stringByTrimmingCharactersInSet( .whitespaceAndNewlineCharacterSet()) } } // 在使用中,核心数据结果可以是 // 有条件地强制转换为协议 class MyController: UIViewController { override func viewDidLoad() { let fr: NSFetchRequest = NSFetchRequest( entityName: "Items") let context = NSManagedObjectContext( concurrencyType: .MainQueueConcurrencyType) do { let items: AnyObject = try context.executeFetchRequest(fr) if let displayItems = items as? [DisplayItem] { print(displayItems) } } catch let error as NSError { print(error.localizedDescription) } } }