使用Swift擴展的“錯誤”方式
大小:0.5 MB 人氣: 2017-10-11 需要積分:1
標簽:SWIFT(23615)
?翻譯如下:非常感謝,這篇文章很不錯。我一直疑惑你為什么要用這么多不必要的擴展,我認為你并未按照正確的用途來使用它們。能否簡單地將它們當作一個整體類?
我使用擴展的主要原因是為了增加可讀性。在這些地方我喜歡使用擴展,盡管“這并不是擴展設計的初衷”。
私有Helper函數
在OC語言中,.h和.m文件維護起來一樣煩人,從.h文件中可以很容易地看出類的外部API,而內部API則保存在.m文件中。但在Swift中,我們只有一個文件。
因此,我們很容易看出類的公共函數:可以從外部及私有部分所訪問的函數。我將私有內部函數放在私有擴展中,如下例:
// it‘s easy to glance and see which parts of this struct are// supposed to be used externallystructTodoItemViewModel { letitem: TodoItem letindexPath: NSIndexPath vardelegate: ImageWithTextCellDelegate { returnTodoItemDelegate(item: item) } varattributedText: NSAttributedString { // the itemContent logic is in the private extension// keeping this code clean and easy to glance atreturnitemContent } } // keeps all this internal logic out of the public-facing API of this struct// MARK: Private Attributed Text Builder Helper Methodsprivateextension TodoItemViewModel { staticvarspaceBetweenInlineImages: NSAttributedString { returnNSAttributedString(string: “ ”) } varitemContent: NSAttributedString { lettext = NSMutableAttributedString(string: item.content, attributes: [NSFontAttributeName : SmoresFont.regularFontOfSize(17.0)]) ifletdueDate = item.dueDate { appendDueDate(dueDate, toText: text) } forassignee initem.assignees { appendAvatar(ofUser: assignee, toText: text) } returntext } func appendDueDate(dueDate: NSDate, toText text: NSMutableAttributedString) { ifletcalendarView = CalendarIconView.viewFromNib() { calendarView.configure(withDate: dueDate) ifletcalendarImage = UIImage.imageFromView(calendarView) { appendImage(calendarImage, toText: text) } } } func appendAvatar(ofUser user: User, toText text: NSMutableAttributedString) { ifletavatarImage = user.avatar { appendImage(avatarImage, toText: text) } else{ appendDefaultAvatar(ofUser: user, toText: text) downloadAvatarImage(forResource: user.avatarResource) } } func downloadAvatarImage(forResource resource: Resource?) { ifletresource = resource { KingfisherManager.sharedManager.retrieveImageWithResource(resource, optionsInfo: nil, progressBlock: nil) { image, error, cacheType, imageURL iniflet_ = image { dispatch_async(dispatch_get_main_queue()) { NSNotificationCenter.defaultCenter().postNotificationName(TodoItemViewModel.viewModelViewUpdatedNotification, object: self.indexPath) } } } } } func appendDefaultAvatar(ofUser user: User, toText text: NSMutableAttributedString) { ifletdefaultAvatar = user.defaultAvatar { appendImage(defaultAvatar, toText: text) } } func appendImage(image: UIImage, toText text: NSMutableAttributedString) { text.appendAttributedString(TodoItemViewModel.spaceBetweenInlineImages) letattachment = NSTextAttachment() attachment.image = image letyOffsetForImage = -7.0asCGFloat attachment.bounds = CGRectMake(0.0, yOffsetForImage, image.size.width, image.size.height) letimageString = NSAttributedString(attachment: attachment) text.appendAttributedString(imageString) } }
注意:在上例中,屬性字符串計算的邏輯超級復雜。如果存在于結構(struct)的主要部分中,我們就無法輕易發現它,并了解哪個部分比較重要了(在OC語言中這個部分是屬于.h文件的)。 這樣做也會使得代碼更干凈。
尤其如果這個屬性字符串在代碼中其他地方還有調用的話,使用這樣的長擴展將邏輯重構到自身結構中會是很好的開頭。不過在編寫代碼時,將它放在私有擴展中會更好。
分組
一開始我在Swift中真正使用擴展的原因在于:Swift剛出來的時候,無法添加pragma mark注釋。沒錯,Swift出現后我想用它做的第一件事就是這個。在OC代碼中,我通過pragma mark來進行區分,換到Swift后還想繼續用。
于是我去了WWDC的Swift Labs,詢問如何在Swift中添加pragma marks,回答者建議我使用擴展來替代。于是我開始使用擴展了,并完全愛上了這種用法。
盡管pragma marks(在Swift中是//MARK)非常棒,但在新寫的代碼中很容易忘記添加MARK,對于編碼風格多樣的團隊來說更是如此。結果就是該MARK的函數沒MARK上,不該加的反而有了。因此,如果一組函數之間相互歸屬,我傾向于將它們放在同一個擴展中。
一般我總會有一個擴展是將所有ViewController或者AppDelegate的初始樣式設計方法歸類到一起的:
private extension AppDelegate { func configureAppStyling() { styleNavigationBar() styleBarButtons() } func styleNavigationBar() { UINavigationBar.appearance().barTintColor= ColorPalette.ThemeColorUINavigationBar.appearance().tintColor= ColorPalette.TintColorUINavigationBar.appearance().titleTextAttributes= [ NSFontAttributeName : SmoresFont.boldFontOfSize(19.0), NSForegroundColorAttributeName : UIColor.blackColor() ] } func styleBarButtons() { let barButtonTextAttributes = [ NSFontAttributeName : SmoresFont.regularFontOfSize(17.0), NSForegroundColorAttributeName : ColorPalette.TintColor] UIBarButtonItem.appearance().setTitleTextAttributes(barButtonTextAttributes, forState: .Normal) } }
或者將所有通知邏輯歸類到一起:
extension TodoListViewController { // called in initfunc addNotificationObservers() { NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector(“onViewModelUpdate:”), name: TodoItemViewModel.viewModelViewUpdatedNotification, object: nil) NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector(“onTodoItemUpdate:”), name: TodoItemDelegate.todoItemUpdatedNotification, object: nil) } func onViewModelUpdate(notification: NSNotification) { ifletindexPath = notification.objectas? NSIndexPath { tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .None) } } func onTodoItemUpdate(notification: NSNotification) { ifletitemObject = notification.objectas? ValueWrapper《TodoItem》 { letupdatedItem = itemObject.valueletupdatedTodoList = dataSource.listFromUpdatedItem(updatedItem) dataSource = TodoListDataSource(todoList: updatedTodoList) } } }
協議一致性
This is a special case of grouping. 我喜歡將所有符合同一個協議的函數放在同一個擴展中。在OC語言中我是用pragma mark來實現的,但我更偏愛擴展的硬分隔和可讀性:
structTodoItemViewModel { staticletviewModelViewUpdatedNotification = “viewModelViewUpdatedNotification”letitem: TodoItem letindexPath: NSIndexPath vardelegate: ImageWithTextCellDelegate { returnTodoItemDelegate(item: item) } varattributedText: NSAttributedString { returnitemContent } } // ImageWithTextCellDataSource Protocol Conformance extension TodoItemViewModel: ImageWithTextCellDataSource { varimageName: String { returnitem.completed ? “checkboxChecked”: “checkbox”} varattributedText: NSAttributedString { returnitemContent } }
用擴展對UITableViewDataSource與UITableViewDelegate進行分割也很奏效。
// MARK: Table View Data Sourceextension TodoListViewController: UITableViewDataSource{ func numberOfSectionsInTableView(tableView: UITableView) -》 Int { returndataSource.sections.count} func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -》 Int { returndataSource.numberOfItemsInSection(section) } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -》 UITableViewCell{ let cell = tableView.dequeueReusableCellWithIdentifier(String.fromClass(ImageWithTextTableViewCell), forIndexPath: indexPath) as! ImageWithTextTableViewCell let viewModel = dataSource.viewModelForCell(atIndexPath: indexPath) cell.configure(withDataSource: viewModel, delegate: viewModel.delegate) returncell } } // MARK: Table View Delegateextension TodoListViewController: UITableViewDelegate{ // MARK: Cell Selectionfunc tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { performSegueWithIdentifier(todoItemSegueIdentifier, sender: self) } // MARK: Section Header Configurationfunc tableView(tableView: UITableView, viewForHeaderInSection section: Int) -》 UIView? { ifdataSource.sections[section] == TodoListDataSource.Section.DoneItems{ let view = UIView() view.backgroundColor= ColorPalette.SectionSeparatorColorreturnview } returnnil} func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -》 CGFloat{ ifdataSource.sections[section] == TodoListDataSource.Section.DoneItems{ return1.0} return0.0} // MARK: Deleting Actionfunc tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -》 Bool { returntrue} func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -》 [UITableViewRowAction]? { let deleteAction = UITableViewRowAction(style: .Destructive, title: “Delete”) { [weakself] action , indexPath in iflet updatedTodoList = self?.dataSource.listFromDeletedIndexPath(indexPath) { self?.dataSource= TodoListDataSource(todoList: updatedTodoList) } } return[deleteAction] } }
模型
我在OC中使用Core Data時非常喜歡使用模型,因為在更改時模型由Xcode生成,因此需要將函數或任何其他內容放入同一個擴展或分類中。
我嘗試盡可能在Swift中使用結構,但還是更喜歡用擴展來分出模型屬性與基于屬性的計算。對我來說,這樣增加了模型代碼的可讀性。
總結
盡管這種做法也許不夠“傳統”,在Swift中對擴展的超簡單運用能極大程度地改善代碼,讓代碼超級具有可讀性。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
下載地址
使用Swift擴展的“錯誤”方式下載
相關電子資料下載
- 拿下國家級信創認證!中科馭數KPU SWIFT-2200N成為國內首款滿足金融業嚴苛要求的 163
- 中科馭數基于DPU的思威SWIFT系列智能網卡與統信軟件產品完成適配 176
- 如何使用Swift提高代碼質量 126
- 積木易搭Magic Swift Plus為雕刻工藝品精雕復刻提供三維數字化解決方案 274
- 詞法分析-Antlr-1 235
- Kotlin 1.8.0發布,改進性能和Swift的互操作性 1044
- Swift 2023:強調并發、泛型和C++互操作性,開發Swift解析器 300
- 彩色套件創建全彩3D模型MagicSwiftPlus僅千元級 432
- Swift的使用體驗與生態發展之路 981
- 如何加速apply函數600倍的技巧 627