讀古今文學網 > iOS編程基礎:Swift、Xcode和Cocoa入門指南 > 9.3 編輯與代碼導航 >

9.3 編輯與代碼導航

Xcode編輯環境的很多地方都可以修改以滿足你的需要。首先應該在Xcode的Fonts & Colors首選項窗格中選擇喜歡的源碼編輯器字體和大小。沒什麼是比舒服地閱讀和編寫代碼更重要的事情了!我喜歡稍大點(13、14,甚至是16)和等寬字體,如Menlo、Consolas或免費的Inconsolata(http://levien.com/type/myfonts/)與Source Code Pro(https://github.com/adobe-fonts/source-code-pro)。

Xcode提供了一些自動格式化、自動輸入與文本選擇特性。其行為取決於你在Xcode的Text Editing首選項窗格的Editing and Indentation頁簽中的設置。這裡並不打算詳細介紹這些設置,但建議你充分利用它們。在Editing下,我習慣勾上所有選項,包括行號;可見的行號在調試時是非常有用的。在Indentation下,我也習慣勾上所有選項;我發現在這些設置下,Xcode能以最佳的方式顯示代碼。

如果喜歡Xcode的智能語法感知縮進,但卻發現有時會有一行代碼並沒有正確縮進,那麼請選擇Editor→Structure→Reindent(Control-I組合鍵),這會自動縮進當前行或所選文本。

勾選「Enable type-over completions」後,Xcode會自動加上分隔符。比如,假設我通過調用初始化器init(frame:)來創建一個UIView。我會這麼寫:


let v = UIView(fr
  

Xcode會自動追加上右圓括號,同時插入點還在右圓括號之前:


let v = UIView(fr)
// I have typed ^
  

不過,這個右圓括號是試探性的;其顏色是灰色。現在輸入參數;輸入完後右圓括號依然是灰色的:


let v = UIView(frame:r)
// I have typed ^
  

現在可以通過幾種方式來確認右圓括號:可以輸入一個右圓括號,也可以按下Tab鍵或向右的方向鍵。這時,試探性的右圓括號會被實際的替換掉,插入點位於其之後了,準備接受後續輸入。雙引號、右花括號以及右方括號的行為與之類似。

9.3.1 自動補令

在編寫代碼時,你會用到Xcode的自動補令特性。Cocoa類型名與方法名非常冗長,無論什麼,只要能節省你輸入代碼的時間都是好事。然而,我並沒有選中Editing下面的「Suggest completions while typing」;相反,我勾選了「Use Escape key to show completion suggestions」,當我希望自動補令時,我會手工實現,通過按下Esc鍵。

比如,我要通過代碼創建一個警告框。我需要輸入UIAlertController(按下Esc會彈出一個菜單,列出適合UIAlertController的4個初始化器,如圖9-2所示)。可以在菜單中導航、關閉它或接受所選,只需使用鍵盤即可。如果默認情況下沒有選中,那麼我會通過向下的方向鍵導航到title:...,然後按下回車鍵將其選中。

圖9-2:自動補令菜單

從自動補令菜單中選擇後,所選方法調用的模板就會輸入代碼中(這裡將其分解為多行顯示):


let alert = UIAlertController(
    title: <#String?#>,
    message: <#String?#>,
    preferredStyle: <#UIAlertControllerStyle#>)
  

<#...#>中的表達式是佔位符,展示了每個參數的類型;它們在Xcode中就像是「文本標記」一樣(如圖9-2所示),防止你不小心修改。可以通過Tab鍵或Navigate→Jump to Next Placeholder(Control-/組合鍵)選擇下一個佔位符。這樣就可以選擇一個佔位符,然後在上面輸入想要傳遞的實參;接下來選擇下一個佔位符並輸入其實參,以此類推。要想將佔位符轉換為一般的字符串且沒有分隔符,可以將其選中並按下回車鍵,或雙擊它。

自動補令與上下文智能感知可用於對像類型名、方法調用與屬性名。在輸入函數聲明時,如果這個函數是繼承下來的,或定義在所使用的協議中,那也可以使用自動補令。你甚至都不需要輸入起始的func;只需要輸入方法名的前幾個字母即可。比如,在我的應用委託類中,我會輸入:


applic
  

如果按下了Esc鍵,那麼我會看到一個方法列表,比如,application:didFinishLaunchWithOptions:,這些是可以發送給應用委託的方法(第11章將會介紹)。如果選擇了一個,那麼其整個聲明都會輸入進來,包括花括號:


func application(application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?)
    -> Bool {
        <#code#>
}
  

代碼佔位符位於花括號之間,它會被選中,等待著我開始輸入函數體。如果函數需要一個override標識,那麼Xcode的代碼補令特性會提供的。

9.3.2 代碼片段

代碼片段是代碼自動補令的有益補充。代碼片段就是個帶有縮寫的一段文本。代碼片段保存在代碼片段庫中(Command-Option-Control-2),不過代碼片段的縮寫對於代碼補令卻是全局的,因此可以使用片段而無須打開庫:輸入縮寫,片段的名字就會出現在代碼補令中。

比如,要想在文件頂部輸入類的聲明,我會輸入class並按下Esc鍵來打開自動補令,然後選擇「Swift Class」或「Swift Subclass」。按下回車鍵後,模板就會出現在代碼中:類名與父類名是佔位符,同時還有花括號,聲明體(位於花括號中)則是另一個佔位符。

要瞭解代碼片段的縮寫,需要打開其編輯窗口(在代碼片段庫中雙擊代碼片段)並單擊Edit。如果覺得記住代碼片段的縮寫太麻煩,可以將其從代碼片段庫中拖曳到文本中。可以通過過濾欄(Edit→Filter→Filter in Library,Command-Option-L組合鍵)根據名字快速找到所需的代碼片段。

可以添加自己的代碼片段,它會劃分到User代碼片段類別中;最簡單的方式就是將文本拖曳到代碼片段庫中。然後編輯它以適應自己的需要,給它起個名字,提供一段說明和一個縮寫;可以通過Completion Scopes彈出菜單縮小代碼補令所顯示的片段上下文。在代碼片段文本中,使用<#...#>結構來構造任何所需的佔位符。

比如,我創建了一個插座變量代碼片段,如下所示:


@IBOutlet var <#name#> : <#type#>!
  

我又創建了一個動作代碼片段,如下所示:


@IBAction func <#name#> (sender:AnyObject!) {
    <#code#>
}
  

我編寫的其他代碼片段構成了一個個人的輔助函數庫。比如,delay代碼片段會插入dispatch_after包裝器函數(參見11.10節)。

9.3.3  Fix-it與實時語法檢查

Xcode的Fix-it特性會針對如何避免問題給出一些積極的建議。要彈出它,請單擊左邊欄的問題標記。編譯後如果有問題會顯示出這種問題標記。

比如,圖9-3頂部顯示我不小心丟掉了方法調用後的圓括號。這會導致編譯錯誤,因為我設置的backgroundColor屬性是個UIColor,它不是函數。不過,錯誤旁邊的停止圖標告訴我Fix-it有個建議。單擊這個停止圖標,圖9-3底部顯示了發生的事情:彈出一個Fix-it對話框,告訴我該如何修復這個問題,即插入圓括號。此外,Xcode也告訴我如果Fix-it按照這種方式修復了問題,那麼代碼會變成什麼樣子。如果按下回車鍵,或雙擊對話框中的「Fix-it」建議,Xcode就會插入圓括號,錯誤會消失不見,因為問題已經得到了解決。

如果相信Xcode的做法是正確的,那麼請選擇Editor→Fix All in Scope(Command-Option-Control-F組合鍵),Xcode會實現周圍所有的Fix-it建議,並且不會再彈出對話框。

圖9-3:帶有Fix-it建議的編譯錯誤

實時語法檢查像是一種持續不斷的編譯。即便沒有編譯或保存,它也可以檢測到存在的問題,並且通過Fix-it給出建議的解決方案。可以通過General首選項窗格中的「Show live issues」復選框打開或關閉該特性。

我覺得實時語法檢查會影響代碼編寫過程。在編寫過程中,代碼幾乎不可能是合法的,因為單詞與圓括號總是半成品;我準備輸入這些內容!比如,僅僅輸入let的首字母就會導致語法檢查器報告無法解析的標識符錯誤;我非常討厭這一點。因此,我並沒有勾選「Show live issues」復選框。

9.3.4 導航

開發Xcode項目需要在多個文件中同時編輯代碼。幸好,Xcode提供了多種方式來導航代碼。前幾章已經介紹了一些。下面是Xcode提供的一些主要的導航方式:

項目導航器

如果你記得文件名的一部分,那麼就可以在項目導航器(Command-1組合鍵)中快速定位到該文件,通過在導航器底部過濾欄中的搜索框內搜索即可(Edit→Filter→Filter in Navigator,Command-Option-J組合鍵)。比如,輸入story就會列出.storyboard文件。此外,在使用完過濾欄後,你可以按下Tab鍵,然後通過向上、向下的方向箭在項目導航器中導航。這樣,只通過鍵盤就能找到所需的文件了。

符號導航器

如果高亮顯示了過濾欄中的前兩個圖標(前兩個是藍色的,第3個是暗色的),那麼符號導航器就會列出項目的對象類型及其成員。單擊符號可以在編輯器中跳轉到其聲明。與項目導航器一樣,過濾欄中的搜索框可以幫助你跳轉到想要去的地方。

跳轉欄

代碼編輯器的跳轉欄的每個路徑組件都是個菜單:

底部

跳轉欄底部(最右邊)是文件中對象與成員聲明的列表,按照它們的顯示順序排序(按住Command鍵的同時選擇菜單可以按照字母表順序查看);可以選擇其一進行導航。

可以通過起始單詞為MARK:的註釋將加粗的章節標題添加到底部菜單中。比如,修改Empty Window項目中的ViewController.swift:


// MARK: - view lifecycle
override func viewDidLoad {
    super.viewDidLoad
}
  

結果就是底部菜單中的viewDidLoad會位於view lifecycle之前。要在菜單中創建分隔符,請輸入一條MARK:註釋,其值是連字符;在上述示例中,連字符(創建一個分隔符行)與標題(創建一個加粗標題)都用到了。與之類似,以TODO:和FIXME:開頭的註釋都會出現在底部菜單中。

上部

上部路徑組件是個層次化菜單;這樣你就可以通過它們遍歷文件層次了。

歷史

每個編輯器窗格都記得你曾經編輯的文件名。向後與向前這兩個三角形既是按鈕也是彈出菜單(或選擇Navigate→Go Back和Navigate→Go Forward,分別對應Command-Control-Left與Command-Control-Right組合鍵)。

相關條目

跳轉欄中最左側的按鈕會彈出相關條目菜單,這是與當前文件相關的一個層次化的文件菜單,比如,父類與所使用的協議等。該列表甚至還包含了當前所選函數調用或被它調用的函數。

跳轉欄中的路徑組件菜單是可以過濾的!打開跳轉欄菜單,輸入文本來過濾菜單所顯示的信息。此處的過濾使用了「智能」搜索而不是嚴格的文本包含搜索;比如,輸入「adf」會找到application:didFinishLaunchingWithOptions:(如果位於菜單中)。

輔助窗格

可以通過輔助窗格同時身處兩處(參見第6章)。按住Option鍵並導航會在輔助窗格而非主編輯器窗格中打開文件。輔助窗格跳轉欄中的Tracking菜單會設定其與主窗格的自動化關係。

頁簽與窗口

還可以通過打開頁簽或單獨的窗口而同時身處兩處(參見第6章)。

跳轉到定義

可以通過Navigate→Jump to Definition(Command-Control-J組合鍵)跳轉到代碼中所選符號的聲明位置處。

快速打開

可以通過File→Open Quickly(Command-Shift-O組合鍵)打開一個對話框,並在這裡搜索代碼和框架頭文件中的符號。

斷點

斷點導航器會列出代碼中的所有斷點。Xcode缺少代碼書籤,不過可以將禁用的斷點當作書籤。本章後面將會介紹斷點。

9.3.5 查找

查找是導航的一種形式。Xcode提供了全局查找(Find→Find in Project,Command-Shift-F組合鍵),這與使用查找導航器的效果是一樣的;還提供了編輯器級別的查找(Find→Find,Command-F組合鍵);不要搞混了。

查找選項是非常重要的。對於編輯器級別的查找,請單擊搜索域中的放大鏡圖標來打開Edit Find Options條目。可以搜索單詞中間部分或單詞開頭,指定是否區分大小寫等,甚至可以使用正則表達式進行查找。這裡有大量的功能!全局查找選項位於搜索框上下,它包含了一個範圍,用於指定搜索哪些文件:單擊當前範圍可以看到Search Scopes面板,可以選擇不同的範圍或創建自定義範圍。

搜索框上方的全局查找選項包含了文本、正則表達式、定義(定義符號的地方)與引用(使用符號的地方)。Xcode 7新增了調用層次查找選項,可以向後追蹤代碼中的調用關係。單擊搜索欄中的第2個條目會顯示一個彈出菜單,選擇Call Hierarchy即可;此外,還可以在代碼中選中一個詞,然後選擇Find→Find Call Hierarchy(Shift-Control-Command-H組合鍵)。調用層次會顯示在查找導航器中(如圖9-4所示)。

要替換文本,請單擊搜索欄最左側的Find來彈出菜單,然後選擇Replace。可以將單詞出現的所有位置都替換掉(Replace All),或在查找導航器中選擇特定的搜索結果,然後只替換這些(Replace);還可以從查找導航器中刪除搜索結果,從而使其不會被Replace All所影響。查找導航器的Preview按鈕會彈出一個對話框,展示了每個可能的替換的效果,可以在執行替換前接受或拒絕特定的替換。對於編輯器級別的查找,在單擊Replace All前按下Option鍵,這樣查找與替換就只會對所選文本起作用。

比較複雜的一種編輯器級別的查找形式是Editor→Edit All In Scope,它會在相同範圍內同時查找所選文本所有出現的地方;可以通過它在範圍內修改變量或函數的名字,或查看名字是怎麼使用的。

圖9-4:查找導航器中的調用層次