使用Swift擴(kuò)展的“錯誤”方式
大小:0.5 MB 人氣: 2017-10-11 需要積分:1
標(biāo)簽:SWIFT(23615)
?翻譯如下:非常感謝,這篇文章很不錯。我一直疑惑你為什么要用這么多不必要的擴(kuò)展,我認(rèn)為你并未按照正確的用途來使用它們。能否簡單地將它們當(dāng)作一個(gè)整體類?
我使用擴(kuò)展的主要原因是為了增加可讀性。在這些地方我喜歡使用擴(kuò)展,盡管“這并不是擴(kuò)展設(shè)計(jì)的初衷”。
私有Helper函數(shù)
在OC語言中,.h和.m文件維護(hù)起來一樣煩人,從.h文件中可以很容易地看出類的外部API,而內(nèi)部API則保存在.m文件中。但在Swift中,我們只有一個(gè)文件。
因此,我們很容易看出類的公共函數(shù):可以從外部及私有部分所訪問的函數(shù)。我將私有內(nèi)部函數(shù)放在私有擴(kuò)展中,如下例:
// 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) } }
注意:在上例中,屬性字符串計(jì)算的邏輯超級復(fù)雜。如果存在于結(jié)構(gòu)(struct)的主要部分中,我們就無法輕易發(fā)現(xiàn)它,并了解哪個(gè)部分比較重要了(在OC語言中這個(gè)部分是屬于.h文件的)。 這樣做也會使得代碼更干凈。
尤其如果這個(gè)屬性字符串在代碼中其他地方還有調(diào)用的話,使用這樣的長擴(kuò)展將邏輯重構(gòu)到自身結(jié)構(gòu)中會是很好的開頭。不過在編寫代碼時(shí),將它放在私有擴(kuò)展中會更好。
分組
一開始我在Swift中真正使用擴(kuò)展的原因在于:Swift剛出來的時(shí)候,無法添加pragma mark注釋。沒錯,Swift出現(xiàn)后我想用它做的第一件事就是這個(gè)。在OC代碼中,我通過pragma mark來進(jìn)行區(qū)分,換到Swift后還想繼續(xù)用。
于是我去了WWDC的Swift Labs,詢問如何在Swift中添加pragma marks,回答者建議我使用擴(kuò)展來替代。于是我開始使用擴(kuò)展了,并完全愛上了這種用法。
盡管pragma marks(在Swift中是//MARK)非常棒,但在新寫的代碼中很容易忘記添加MARK,對于編碼風(fēng)格多樣的團(tuán)隊(duì)來說更是如此。結(jié)果就是該MARK的函數(shù)沒MARK上,不該加的反而有了。因此,如果一組函數(shù)之間相互歸屬,我傾向于將它們放在同一個(gè)擴(kuò)展中。
一般我總會有一個(gè)擴(kuò)展是將所有ViewController或者AppDelegate的初始樣式設(shè)計(jì)方法歸類到一起的:
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) } } }
協(xié)議一致性
This is a special case of grouping. 我喜歡將所有符合同一個(gè)協(xié)議的函數(shù)放在同一個(gè)擴(kuò)展中。在OC語言中我是用pragma mark來實(shí)現(xiàn)的,但我更偏愛擴(kuò)展的硬分隔和可讀性:
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 } }
用擴(kuò)展對UITableViewDataSource與UITableViewDelegate進(jìn)行分割也很奏效。
// 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時(shí)非常喜歡使用模型,因?yàn)樵诟臅r(shí)模型由Xcode生成,因此需要將函數(shù)或任何其他內(nèi)容放入同一個(gè)擴(kuò)展或分類中。
我嘗試盡可能在Swift中使用結(jié)構(gòu),但還是更喜歡用擴(kuò)展來分出模型屬性與基于屬性的計(jì)算。對我來說,這樣增加了模型代碼的可讀性。
總結(jié)
盡管這種做法也許不夠“傳統(tǒng)”,在Swift中對擴(kuò)展的超簡單運(yùn)用能極大程度地改善代碼,讓代碼超級具有可讀性。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%
下載地址
使用Swift擴(kuò)展的“錯誤”方式下載
相關(guān)電子資料下載
- 拿下國家級信創(chuàng)認(rèn)證!中科馭數(shù)KPU SWIFT-2200N成為國內(nèi)首款滿足金融業(yè)嚴(yán)苛要求的 163
- 中科馭數(shù)基于DPU的思威SWIFT系列智能網(wǎng)卡與統(tǒng)信軟件產(chǎn)品完成適配 176
- 如何使用Swift提高代碼質(zhì)量 126
- 積木易搭Magic Swift Plus為雕刻工藝品精雕復(fù)刻提供三維數(shù)字化解決方案 274
- 詞法分析-Antlr-1 235
- Kotlin 1.8.0發(fā)布,改進(jìn)性能和Swift的互操作性 1044
- Swift 2023:強(qiáng)調(diào)并發(fā)、泛型和C++互操作性,開發(fā)Swift解析器 300
- 彩色套件創(chuàng)建全彩3D模型MagicSwiftPlus僅千元級 432
- Swift的使用體驗(yàn)與生態(tài)發(fā)展之路 981
- 如何加速apply函數(shù)600倍的技巧 627