面向协议的程序设计可以用作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)
}
}
}