作者:Soroush Khanlou,原文鏈接,原文日期:2016-09-27
譯者:saitjr;校對(duì):CMB;定稿:CMB
可以說 Swift 是 Objective-C 的后繼之人,畢竟也算是師出同門。但是他們語(yǔ)法看來不像,用起來也不像,給人的感覺也不一樣。有些在 Objective-C 上用得好端端的案例,在 Swift 上卻看起來怪怪的,如方法命名。在 Objective-C 中,方法名盡量完整:
objective-c
[string dataUsingEncoding:NSUTF8StringEncoding];
在 Swift 2.2 中,這樣調(diào)用看著就沒那么優(yōu)雅:
string.dataUsingEncoding(NSUTF8StringEncoding)
在 Swift 3 中,這個(gè)方法看起來就順眼多了:
string.data(using: .utf8)
所以,像 Swift 3 中這樣的命名方式,才是 Swift 的正確姿勢(shì)。而 Objective-C 的方式也只適用于 Objective-C。我覺得這篇文章應(yīng)該能幫你在新世界中修煉你的方法命名習(xí)慣。
無論是三方框架,還是平時(shí)開發(fā)中編寫的代碼,都應(yīng)該更新為更為 Swift 的方式。下面,我將著重說一下代理的命名。
Swift 中代理的理解和 Objective-C 并不完全相同。Objective-C 偏向于 “發(fā)送者” 與 “接收者”。Apple 的 Objective-C 文檔也傾向于這種方式。比如 UIResponder
的 isFirstResponder
方法,文檔上是這樣解釋的:
Returns a Boolean value indicating whether the receiver is the first responder.
返回一個(gè)接收者是否是第一響應(yīng)者的標(biāo)識(shí)(布爾值)。
所以,在設(shè)置 target-action 的時(shí)候,參數(shù)名理所當(dāng)然的稱為 sender
:
objective-c
- (void)buttonTapped:(UIButton *)sender {
代理方法的定義規(guī)則和這個(gè)類似:在 Objective-C 中,代理方法的第一個(gè)參數(shù)總是發(fā)送者。讓我們來看看為什么會(huì)這樣:如果你(接收者,即實(shí)現(xiàn)代理方法的對(duì)象)是多個(gè)相同類型對(duì)象的代理,那么你需要這個(gè)參數(shù)來進(jìn)行區(qū)分。所以代理方法提供了第一個(gè)參數(shù),方便分別處理。(譯注:例如多個(gè) UITextField
的 delegate
都是 self
的時(shí)候,就需要進(jìn)行區(qū)分是哪個(gè) UITextField
調(diào)用的代理方法)。
下面我會(huì)用到 Backchannel SDK 中的例子,為了簡(jiǎn)單起見,我簡(jiǎn)化了一些類名。
這個(gè) SDK 中代理方法分為兩大類。第一類是事件觸發(fā)的代理:
objective-c
- (void)messageFormDidTapCancel:(BAKMessageForm *)messageForm;
在 Swift 中,翻譯為:
func messageFormDidTapCancel(_ messageForm: BAKMessageForm)
這要放在 Swift 3 中就不那么順眼了。在 Swift 3 中,應(yīng)該去調(diào)冗余部分(messageFrom
重復(fù)了),并且第一個(gè)參數(shù)應(yīng)該有別名,而不應(yīng)該用下劃線代替。
第二類是事件觸發(fā),并且還帶有部分?jǐn)?shù)據(jù)的代理方法。對(duì)于這類,我舉了以下兩個(gè)例子:
objective-c
- (void)messageForm:(BAKMessageForm *)messageForm didTapPostWithDraft:(BAKDraft *)draft;
- (void)messageForm:(BAKMessageForm *)messageForm didTapAttachment:(BAKAttachment *)attachment;
在 Swift 中,翻譯為:
func messageForm(_ messageForm: BAKMessageForm, didTapPostWithDraft draft: BAKDraft)
func messageForm(_ messageForm: BAKMessageForm, didTapAttachment attachment: BAKAttachment)
簡(jiǎn)直辣眼睛。為啥兩個(gè)方法都叫 messageFrom
?并且這個(gè)方法開頭的名詞也不合常理:一般建議名詞是方法返回的對(duì)象類型(比如 NSString
的 data(using:)
,就是返回的 Data
)。但是這個(gè)例子中,卻并不需要返回任何 “message form”。這里指的 “message form”其實(shí)應(yīng)該是第一個(gè)參數(shù)的名字,真是個(gè)令人糾結(jié)的方法名。
其實(shí)這兩種類型的代理方法,都可以通過將“sender”移到行末,把動(dòng)詞提到最前來解決命名的問題。對(duì)于第一個(gè)例子來說,是 sender 想告訴代理點(diǎn)擊取消事件(didTapCancel
),而不是 messageFormDidTapCancel
,所以應(yīng)該改為:
func didTapCancel(messageForm: BAKMessageForm)
這樣看起來好多了。事件的名稱被提在了最前作為方法名,能很直觀的看出方法的作用。我覺得,最好再將介詞作為參數(shù)別名,這樣調(diào)用的時(shí)候就更優(yōu)雅了:
func didTapCancel(on messageForm: BAKMessageForm)
目前我還沒找到關(guān)于介詞的使用規(guī)范。不過我會(huì)在不同情況下,選擇使用“on”,“for”,“with”,“in”。用戶是點(diǎn)擊在表單“上”的,所以我覺得這里用“on”比較合適。
接下來再來看看,代理方法有數(shù)據(jù)返回的情況。將動(dòng)詞提到最前,選擇合適的介詞就能有效解決這個(gè)問題了。
之前是:
func messageForm(_ messageForm: BAKMessageForm, didTapPostWithDraft draft: BAKDraft)
而更 Swift 化的是:
func didTapPost(with draft: BAKDraft, on messageForm: BAKMessageForm)
和
func didTap(attachment: BAKAttachment, on messageForm: BAKMessageForm)
這種命名規(guī)則只是我歸納出來的,并沒有經(jīng)過他人印證,但我覺得這要比現(xiàn)在代理方法命名的規(guī)則要好得多。之后,我可能還會(huì)自己的 Swift 代理方法中使用這種規(guī)則。
下面列舉了 UITableView
的 delegate 與 data source 方法,以及這些方法在未來可能的樣子:
func numberOfSections(in tableView: UITableView) -> Int
numberOfSections
遵循了前文提到的規(guī)則,看起來很優(yōu)雅。
但其余的方法看起來就不那么好了:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
更為漂亮的命名是:
func numberOfRows(inSection section: Int, in tableView: UITableView) -> Int
func cellForRow(at indexPath: IndexPath, in tableView: UITableView) -> UITableViewCell
func didSelectRow(at indexPath: IndexPath, in tableView: UITableView)
本文由 SwiftGG 翻譯組翻譯,已經(jīng)獲得作者翻譯授權(quán),最新文章請(qǐng)?jiān)L問 http://swift.gg。