原文地址:http://download.csdn.net/download/fjp1230123/9138833html
跟隨iOS開發技術發展的潮流,我將持續維護本文檔的中文版,若是你喜歡這個譯本,也請給個 Star 鼓勵下~~react
本文檔的英文原版在這裏,感謝Futurice團隊卓越的工做,爲咱們提供這麼優質的文檔。android
知識是人類進步的階梯ios
翻譯,喵 ~~git
就像一個軟件項目同樣,這份文檔若是咱們不持續維護就會逐漸失效,咱們鼓勵你們參與到這個項目中來---僅需提交一個 issue 或發送一份 pull requestgithub
對其餘移動平臺感興趣?個人Andriod開發最佳實踐以及Windows App開發最佳實踐可能會幫到你哦。web
iOS開發要上手比較困難,由於不管是 Objective-C 仍是 Swift 在別處都沒有普遍被應用,iOS 這個平臺彷佛對一切都有一套不一樣的叫法。當你嘗試在真機上跑程序時不免會磕磕碰碰。這份持續更新的文檔就是你的救星!不管你是Cocoa王國的新手,或是老練到只想知道"最佳作法"是什麼,這份文檔都值得一讀。固然,內容僅供參考,你有理由採起不一樣的作法只要你願意!objective-c
若是你想閱讀指定的小節,能夠經過目錄直接跳轉數據庫
Xcode是絕大多數 iOS 開發者選擇的 IDE,也是 Apple 惟一一個官方支持的 IDE. 也有一些其餘的選擇,最著名的可能就是 AppCode了。但除非你已經對 iOS 遊刃有餘,不然仍是用 Xcode 吧,儘管 Xcode 有一些缺點,但它如今還算是至關實用的!express
要安裝 Xcode ,只需在 Mac 的 AppStore 上下載便可。它自帶最新版的 SDK 和 iOS 模擬器,其餘版本能夠在 Preferences > Downloads處安裝。
開始一個新的 iOS 項目時,一個常見的問題是:界面用代碼寫仍是用 Storyboard、xib來畫?現有的 App 中兩種方式都佔有至關的市場。就此咱們須要考慮如下幾點:
用代碼寫界面有啥好處?
用 Storyboard 畫界面有啥好處?
爲何不一樣時使用二者?
爲告終合二者之間的優勢,你也能夠採用一種混合的方法:使用 Storyboard 繪製最初的設計,對於時不時要作出改變修修補補來講很是合適,你甚至能夠邀請設計師參與到這個過程當中來。當 UI 的設計更爲成熟和可靠時,你再過分到代碼層進行配置,這有利於相互合做及代碼的維護。
要爲一個項目添加版本控制,最好第一步就添加一個恰當的.gitignore
文件。這樣一來不須要的文件(如用戶配置、臨時文件等)就不會進入 repository(版本倉庫)了。可喜的是,Github 已經幫咱們準備了 Objective-C版 和 Swift版。
若是你準備在工程中引入外部依賴(例如第三方庫),Cocoapods提供了快速而便捷的集成方法。安裝方法以下:
sudo gem install cocoapods
首先進入你的工程目錄,而後運行
pod init
這樣會建立一個 Podfile 文件,在這裏集中管理全部的依賴。添加你所須要的依賴而後運行
pod install
來安裝這些庫,並把它們和你的工程一塊兒放進一個 workspace
裏。在 commit 的時候,推薦把依賴庫在你的 repo 裏安裝好以後再 commit,最好不要讓每一個開發者 checkout
後還要本身跑一下 pod install
。
注意:今後之後要用.workspace
打開工程,不要再用.xcproject
打開,不然代碼編譯不經過。
下面這條指令:
pod update
會把全部的 pod 都更新到 Podfile 容許的最新版本。你能夠經過一系列的 語法來準確指定你對版本的要求。
把這些數以百計的源文件都保存在同一目錄下,不根據工程結構來構建一個目錄結構是沒法想象的。你可使用下面的結構:
|- Models |- Views |- Controllers |- Stores |- Helpers
首先,在 Xcode 的 Project Navigator (左邊欄)裏,把這些目錄創建爲group (小小的黃色"文件夾"),建在工程的同名 group 下。而後,把每個 group 與工程路徑下實際的文件夾連接起來,方法是:
一開始就應該把全部的文案放在本地化文件裏,這不只有利於翻譯,也能讓你更快地找到面向用戶的文本。你能夠在 build scheme 裏添加一個 launch 參數,指定在某種語言下啓動 App,例如:
-AppleLanguages (Finnish)
對於更復雜的翻譯,好比與名詞的數量有關的複數形式(如 "1 person" 對應 "3 people"),你應該使用 .stringsdict
格式來替換普通的 localizable.strings
文件。只要你能習慣這種奇葩的語法,你就擁有了一個強大的工具,你能夠根據須要(如俄語或阿拉伯語的規則)把名詞變爲"一個"、"一些"、"少數"和"許多"等複數形式。
更多關於本地化的信息,請參考2012年2月的Helsink iOS會議的幻燈片。其中大部分演講至少到2014年10月爲止仍然不過期!
建立被 prefix header 引入的一個 Constants.h
文件
不要用宏定義( #define
),用實際的常量定義
static CGFloat const XYZBrandingFontSizeSmall = 12.0f; static NSString * const XYZAwesomenessDeliveredNotificationName = @"foo";
常量類型安全並有更明確的做用域(在全部沒有引入的文件中不能使用),不能被重定義,而且能夠在調試器中使用。
App發佈的時候把 Release 代碼從原有的分支上隔離出來,而且加上適當的tag,是很好的作法,對於向公衆分發(好比經過Appstore)的 app 這一點尤爲重要。同時,涉及大量 commit 的 feature 應該在獨立的分支上完成。 git-flow
是一個幫助你遵照這些規則的工具。它只是在 git 的分支和 tag 命令上簡單加了一層包裝,就能夠幫助維護一套適當的分支結構,對於團隊協做尤其有用。全部的開發都應該在 feature 對應的分支上完成(小改動在 develop 分支上完成),給 release 打上 app 版本的 tag,而後 commit 到 master 分支時只能用下面這條命令:
git flow release fininsh <version>
通常來講,在工程裏添加外部依賴要謹慎。固然,眼下某個第三方庫能漂亮地解決你的問題,但或許不久以後就陷入了維護的泥淖,最後隨着下一版 OS 的發佈全線崩潰。另外一種狀況是,原先只能經過引用外部庫來實現的 feature,忽然官方 API 也支持了。在設計良好的項目裏,把第三方庫替換爲官方的實現花不了多少功夫,但在未來會大有裨益。永遠要優先考慮用蘋果官方的框架(也是最好的框架)來解決問題!
所以,這一章有意寫得比較簡短。下面介紹的第三方庫主要用來減小模板代碼(例如 Auto Layout)或者用來解決複雜的、須要大量測試的問題,例如計算日期。隨着你對 iOS 愈來愈精通,務必要四處看看它們的源碼,熟悉它們所使用的底層框架。你會發現作好這些就能減輕許多重擔了。
99.95% 的 iOS 開發者使用這個庫,當 NSURLSession 本身自己也很是完善的時候, AFNetworking 仍然能憑藉不少 App 需求的隊列請求管理能力立於不敗之地。
總的來講,不要本身計算日期。DateTools 是一個通過完全測試的開源庫,你能夠放心使用它來作這種事情。
若是你更喜歡用代碼寫界面,你會用過 Apple 難用的 NSLayoutConstraint
的工廠方法或者 Visual Format Language
。前者很囉嗦,後者基於字符串不利於編譯檢查。
masonry 經過他本身的 DSL 來建立、更新和替換約束,利用語言豐富的操做符重載特性較優雅地實現了 AL。Swift 中一個相似的庫是 Cartography。若是更加保守的話, FLKAutoLayout 是一個好的選擇,它爲原生API添加了一層簡潔而不奇異的包裝。
RACSignal
,或是返回值爲 void
,參數中帶有自定義的 completion block
的方法。如下是組建之間互發通知的一些常見手段:
events
給多個觀察者的方法。耦合性很是鬆 - 沒有任何對當前派發對象的引用的狀況下,通知也可以在全局範圍內被觀察到。要確保你的 Model 是不可變的,他們用來把遠程 API 的語義和類型轉換爲 App 適用的語義和類型。對Objective-C來講 Github的Mantle是個不錯的選擇。在 Swift 中,你可使用 structs 而非 classes 來確保其不可變性,並使用一個相似 SwiftyJSON或者 Argo的解析庫來作 JSON - Model 之間的轉換。
今天 Apple 生態系統中豐富的屏幕尺寸及分屏多任務 iPad 的問世,使得設備和它的構成形式之間的界限愈來愈模糊。就像今天的網站要預先適配不一樣的窗口尺寸同樣,你的 App 也應該以一種優雅的方式來處理各類屏幕的尺寸變化。用戶旋轉設備或者在你的 App 旁邊滑動第二個 iPad App 時(分屏多任務),這種需求簡直是必須的。
你應該使用size classes和 AutoLayout 來申明你的視圖約束,而不是直接操做視圖的 frame。基於這些約束規則,系統將爲視圖 計算合適的 frame 並在環境改變時(切換設備或者分屏展現等)從新計算他們。
Apple 在設置佈局約束的推薦方法中推薦在初始化方法中建立並激活你的佈局約束.若是你須要動態地改變某些約束,hold 住他們的引用並在必要的時候關閉或激活他們。這主要用於在你想要系統執行批量更新以獲取更好性能的時候, 執行 UIView
的 updateConstraints
(或者它對應的 UIViewController
的 updateViewContraints
)。但這樣作的代價是你須要調用 setNeedsUpdateConstraints
方法, 這會增長代碼的複雜性。
若是你在自定義的視圖中重寫 updateConstraints
,你應該明確指出你的視圖支持基於約束的佈局:
Swift:
override class func requiresConstraintBasedLayout() -> Bool { return true; }
Objective-C:
+ (BOOL)requiresConstraintBasedLayout { return YES; }
否則,系統可能不會如期調用 -updateConstraints
,而致使奇怪的 bug 。這一點上 Edward Huynh 提供的這個博客有更詳細的解釋。
要使用依賴注入,也就是說,應該把 controller 須要的數據用參數傳進來,而非把全部的狀態都保持在單例中。後者僅當這些狀態的確是全局狀態的狀況下才適用。
Swift:
let fooViewController = FooViewController(viewModel: fooViewModel)
Objective-C
FooViewController *fooViewController = [[FooViewController alloc] initWithViewModel:fooViewModel];
儘可能避免在 view controller 中引入大量的本能夠安全地放在其餘地方實現的業務邏輯,這會讓 view Controller 變得十分臃腫。Soroush Khanlou 有一篇 很好的博客 介紹瞭如何實現這種機制,而相似 MVVM 這樣的程序架構將 view controller 當 views 對待,所以大大地減小了 view controller 的複雜度。
//GigStore.h typedef void (^FetchGigsBlock)(NSArray *gigs, NSError *error); - (void)fetchGigsForArtist:(Artist *)artist completion:(FetchGigsBlock)completion; //GigStore.m [GigStore sharedStore] fetchGigsForArtist:artist completion:^(NSArray *gigs, NSError *error) { if(!error) { //Do something with gigs } else { // :( } };
這樣雖可行,但若是要發起幾個鏈式請求,很容易致使回調深淵。
若是你身陷回調深淵,能夠看看 ReactiveCocoa(RAC).這是一個多功能、多用途的庫,它能夠改變整個 App 的寫法。但你也能夠僅在適合用它的時候,零散地用一下。
Teehan+lax以及NSHipster很好地介紹了 RAC 概念(以及整個 FRP 的概念)。
//GigStore.h - (RACSignal *)gigsForArtist:(Artist *)artist; //GigsViewController.m [[[GigStore sharedStore] gigsForArtist:artist] subscribeNext:^(NSArray *gigs) { // Do something with gigs } error:^(NSError *error) { // :( }];
在這裏咱們能夠把 gig(演出) 信號與其餘信號結合,所以能夠在展現 gig 以前作一些修改、過濾等處理。
做爲一個能夠"在地面上移動"的移動應用,一般有某種存儲模型把數據保存在某個地方,如硬盤上、本地數據庫中或者遠程的服務器上。在把模型對象的任意活動抽象出來的方面,Store 層也很是有用。
抓取數據一般是異步進行的,但它是意味着關閉後臺請求仍是從硬盤反序列化一個大文件呢?你的 Store 層的 API 必須經過提供某種延期機制反映出這種狀況,就像同步返回數據將引發線程阻塞那樣。
若是你使用 ReactiveCocoa, 一般會選擇 SignalProducer
做爲返回類型。舉個栗子,獲取某個藝術家的演出信息將會產生下面這樣 Signature:
Swift + RAC 3:
func fetchGigsForArtist(artist: Artist) -> SignalProducer<[Gig], NSError> { //... }
Objective-C + RAC 2:
- (RACSignal *)fetchGigsForArtist:(Artist *)artist { //... }
這裏,返回的 SignalProducer
僅僅是獲取演出列表的一個"配方"。僅當被訂閱者(如:一個 viewModel )啓動時纔會執行獲取演出列表的實際的動做,在數據返回前取消訂閱將會取消該網絡請求。
若是你不想使用信號、"期貨"或相似的機制來表明你將來的數據,你也可使用常規的 block 回調。但要記住,block 塊嵌套地進行鏈式調用,如在某個網絡請求依賴於另外一個的結果的狀況下,就會迅速變得很是笨重 --- 這種狀況一般被稱爲「回調深淵"。
Asset catalogs是管理你全部項目可視化資源的最好方式,他們能夠同時管理通用的以及設備相關的(iPhoen4-inch,iPhone Retina,iPad 等)資源,而且會經過他們的名字自動分組。告訴你的設計師如何添加它們,(Xcode有內建的 Git 客戶端)能夠節省不少時間,不然你會不少時間從郵件或者其餘渠道把它們複製到代碼庫中。同時,這樣也可讓設計師即刻看到本身的改動,能夠根據需求進行迭代。
Asset catalog 只會暴露出一套圖片的名字,省略了每張圖片實際的文件名。這樣相似 button_large@2x.png
這類文件的命名空間僅限於 asset 內部,很好地避免了 asset 的命名衝突。然而,命名 asset 時遵循一些原則可讓生活更輕鬆:
IconCheckmarkHighlighted.png // Universal, non-Retina IconCheckmarkHighlighted@2x.png // Universal, Retina IconCheckmarkHighlighted~iPhone.png // iPhone, non-Retina IconCheckmarkHighlighted@2x~iPhone.png // iPone, Retina IconCheckmarkHighlighted-568@2x~iPhone.png // iPhone, Retina, 4-inch IconCheckmarkHighlighted~iPad.png // iPad, non-Retina IconCheckmarkhighlighted@2x~iPad.png // iPad, Retina
其中的 -568h
、@2x
、~iPhone
以及~iPad
這些標示符本省並非必需的,但若是在文件名里加上它們,把文件拖動到 asset 時就能自動落到正確的"格子"上,所以能避免難以察覺的錯誤拖放。
你能夠把設計師設計的原始圖矢量圖(PDFs)放進 Asset catalog,讓 Xcode 來自動生成位圖。這樣能減小工程的複雜度(減小文件的個數)。
Apple 很是注意在 API 中保持命名一致性,即使是很是冗長的命名也如此。作 cocoa 開發時要遵循 Apple的命名規範, 這樣能讓加入項目的新人輕鬆許多。
如下是幾條看了就能用上的基本規則:
以動詞開頭的方法,表示它執行的操做會形成一些影響( 譯者注:有時候是函數反作用 ),可是不返回任何值。
- (void)loadView;
或者 - (void)startAnimating;
如下注釋來自"維基魔杖"
在計算機科學中,函數反作用指當調用函數時,除了返回函數值以外,還對主調用函數產生附加的影響。例如修改全局變量(函數外的變量)或修改參數。
函數反作用會給程序設計帶來沒必要要的麻煩,給程序帶來十分難以查找的錯誤,而且下降程序的可讀性。嚴格的函數式語言要求函數必須無反作用。
任何以名字開頭的方法,應該返回一個對象而且不能形成額外的影響 (即不帶函數反作用)。
- (UINavigationItem *)navigationItem;
+ - (UILabel *)labelWithText:(NSString *)text;
儘量地區分這兩種方法有不少好處。好比當您轉換數據的時候就不該該形成額外的影響 ( 譯者注:即函數反作用。數據轉換的時候即上面那些使用名字開頭的方法,其實是一種數據轉換的方法),反過來也同樣(沒有函數反作用的函數應該返回某個對象,具體可參考嚴格意義上的函數式語言的要求)。這樣的話可讓具備函數反作用的代碼保持在一個小的比較集中的區域內,能夠幫助理解代碼並有利於 Debug.(相似咱們的初始化全局變量的方法或者那些設置控制屬性的方法等)
Pragma marks是給方法分組很好的方法,特別是在 ViewController 中。下面是 swift/Objective-C 語言的一個在 viewController 中常見的結構:
Swift MARK 風格:
import someExternalFramework class FooViewController : UIViewController, FoobarDelegate { let foo: Foo private let fooStringConstant = "FooConstant" private let floatConstant = 1234.5 //MARK: LifeCycle //Custom initializers go here //MARK: View LifeCycle override func viewDidLoad() { super.viewDidLoad() // ... } //MARK: Layout private func makeViewConstaints() { // ... } //MARK: User Interaction func foobarButtonTapped () { // ... } //MARK:FoobarDelegate func foobar(foobar: Foobar didSomethingWithFoo foo: Foo) { // ... } //MARK: Additional Helpers private func displayNameForFoo(foo: Foo) { // ... } }
Objective-C MARK風格:
#import "someModel.h" #import "someView.h" #import "someController.h" #import "someStore.h" #import "someHelper.h" #import <someExternalLibrary/someExternalLibraryHeader.h> static NSString * const XYZFooStringConstant = @"FoobarConstant"; static CGFloat const XYZFooFloatConstant = 1234.5; @interface XYZFooViewController () <XYZBarDelegate> @property (nonatomic, readonly, copy) Foo *foo; @property (nonatomic, strong) UILabel *label; //譯者加 @end @implementation XYZFooViewController #pragma mark - LifeCycle - (instancetype)initWithFoo:(Foo *)foo; - (void)dealloc; #pragma mark - View LifeCycle - (void)viewDidLoad; - (void)viewWillAppear:(BOOL)animated; #pragma mark - Layout - (void)makeViewConstraints; #pragma mark - Public Interface - (void)startFooing; - (void)stopFooing; #pragma mark - User Interface - (void)foobarButtonTapped; #pragma mark - XYZFoobarDelegate - (void)foobar:(Foobar *)foobar didSomethingWithFoo:(Foo *)foo; #pragma mark - Internal Helpers - (NSString *)displayNameForFoo:(Foo *)foo; #pragma mark - Setter / Getter (譯者加) - (UILabel *)label; @end
最重要的是讓這些分塊標記在工程裏全部的類裏保持一致!
Futurice(做者所在的公司)並無公司範圍的編碼風格指南。不過,仔細研究一下其餘開發社區的 Objective-C 風格指南會很是有用,儘管有些部分可能只對特定公司有效或比較主觀。
即便在這樣一個時代,咱們信任咱們的便攜設備,讓其攜帶本身最私有的數據,但 app 的安全性仍然是一個常常被忽視的主題。嘗試對數據安全性的設定找到一個良好的權衡,如下有一些簡單的經久耐用的法則。另外,Apple 的 iOS安全指南是一個很好的入門教程。
若是你的 app 須要存儲敏感數據,好比用戶名、密碼、認證 "Token" 或者一些我的的用戶信息,你須要將它們保存在本地且不容許從 App 外部進行讀取。毫不能用 NSUserDefaults
或別的存放在閃存的 plist 文件,也不能用 CoreData 來作,由於他們沒有加密!絕大多數相似的狀況,iOS KeyChain
是你的救星。若是不習慣直接使用 C 的 APIs,你可使用像 SSKeyChain或者 UICKeyChainStore 這樣的一些封裝。
在保存文件和密碼時,確保正確而謹慎地選擇恰當的安全等級。若是在設備鎖定時(好比後臺任務)你還須要訪問文件,使用 "accessible after first unlock" 選項便可。其餘的狀況下,你應該要求設備在解鎖以後才能訪問數據。僅在須要使用敏感數據時纔讀取。
確保任什麼時候候與服務端的 HTTP 通訊都是 TLS 加密的。爲避免中間人攻擊竊聽你的加密數據,你能夠設置證書約束(certificate pinning),像 AFNetworking或Alamofire這種流行的網絡庫都支持這樣通訊。
發佈你的 app 以前,應特別當心地設置好合適的日誌級別。構建的產品(ipa文件)毫不能(日誌)記錄登陸密碼、API的Tokens等相似的敏感信息,由於這很容易致使將他們泄露給公衆。另外一方面,記錄基本的控制流程能夠幫你定位用戶所遇到的問題。
當使用 UITextField
作密碼輸入時,記住設置它們的 secureTextEntry
屬性爲 true
,以避免明文顯示密碼。同時也應該關閉其"輸入自動校訂"的功能,並在任何合適的時刻清空密碼,好比當 app 退到後臺時。
當 app 退到後臺時,清空剪切板能夠避免密碼或其餘敏感數據被泄露。因爲 iOS 可能須要你 app 的屏幕截圖,以顯示在 app 切換器中,因此在 applicationDidEnterBackground
方法返回前,應該確保 UI 上顯示的全部敏感數據被清空。
建議把編譯警告都打開,而且像對待 error 同樣對待 warning。這份幻燈片論證了這一點。幻燈片裏同時還講到了如何在特定文件或特定代碼段中忽略特定的 warning。
一句話,在 build setting 的 "Other Warning Flags"中至少要加入如下兩個值:
-Wall
(開啓很是多的額外的 warning)-Wextra
(開啓許多額外的 warning)同時打開 build setting 裏的 "Treat warnings as errors"
Clang 編譯器 (也就是 Xcode 適用的編譯器) 有一個靜態分析器(static analyer),用來執行代碼控制流和數據流的分析,能夠發現許多編譯器檢查不出來的問題。
你能夠在 Xcode 的 Product ---> Analyze裏手動運行分析器。
分析器能夠運行"shallow"和"deep"兩種模式。後者要慢不少,可是有跨方法的控制流分析以及數據流分析,所以能發現更多問題。
建議:
由咱們員工Ali Rantakari創做的 Faux Pas 是一個出色的靜態 Error 檢測工具。它能分析你的代碼庫,找出你全然不知的錯誤。在發佈任何iOS (或 Mac)App以前務必要運行它一次!
當 App 崩潰時,默認狀況下 Xcode 不會進入 Debugger。要想進入 Debugger,須要添加一個 Exception Breakpoint (點擊 Xcode 的 Debug Navigator 底部的"+"號),遇到 Exception 時就會暫停執行。在大部分狀況下,你都能看到致使 Exception 的那行代碼。 這種方法會捕捉到任何 Exception,包括已經作了處理的 Exception。若是Xcode常常停在良性的 Exception 上(好比第三方庫),選擇 Edit Breakpoint而後在 Exception 下拉菜單中選擇 Objective-C能夠減小這種狀況的出現。
在 View 的 Debug 方面, Reveal和Spark Inspector是兩個強大的可視化檢查器,能夠節約你大量的時間,尤爲是用 AutoLayout 時想知道消失的視圖去哪兒了的狀況。 Xcode 也免費提供了一個相似的東西,不過只支持 iOS8 + ,而且還不夠完善。
Xcode 自帶一套評測工具 "Instruments"。它包含了衆多的評測工具:評測內存使用、CPU、網絡鏈接、圖像等等。它自己是個龐然大物,但一個比較簡單直接的用途是用 Allocations Instrument 來檢測內存泄露。只需在 Xcode 中選擇 Product ---> Profile,選擇 Allocations instrument,點擊 Record按鈕,而後從 Allocation Summary中過濾一些有用的字符串,好比 app 中你本身寫的類的類名前綴。在 Persistant一欄中的計數顯示了每一個對象有多少個實例。若是某個類的實例個數一直胡亂增加,說明有內存泄露。
衆所周知的是 Instruments 有一個 Automation 工具能夠把 UI 交互錄製爲 JavaScript 文件並重放。UI Auto Monkey是一個腳本,它能夠藉助 Automation 在你的 App 上隨機點擊、清掃、旋轉,這對壓力測試/浸泡測試頗有幫助。
要格外注意的是,你在哪裏以何種方式建立了巨耗資源的類。舉個栗子,NSDateFormatter
建立起來很是耗資源,當快速而連續這麼作時,好比在 tableView:cellForRowAtIndePath:
方法中,會真正減慢 App 的響應速度。你應該建立一個它的 static 實例,並在須要格式化日期時直接使用該實例。
強烈推薦在你的 App 中添加一個統計分析的框架,它能幫助你看到用戶其實是怎麼用你的 App 的。X 功能有價值嗎?按鈕 Y 太難找到了嗎?要回答這些問題,能夠把點擊事件、計時以及其餘可測的信息發送到一個能收集並可視化這些信息的服務上,好比 Google Tag Manager。Google Tag Manager 比 Google Analytics 更靈活一些,它在 App 和 Analytics 之間插了一個數據層,所以不須更新 app 就能夠經過 web service 更改數據邏輯。
一種好的作法是加一個輕量的輔助類,好比 XYZAnalyticsHelper
,用來把 App 內部的 model 和數據格式(XYZModel, NSTimeInterval等)翻譯成以字符串爲主的數據層。
Swift :
fun pushAddItemEventWithItem(item: Item, editMode: EditMode) { let editModeString = nameForEditMode(editMode) pushToDataLayer([ "event" : "addItem", "itemIdentifier" : item.identifier, "editMode" : editModeString ]) }
Objective-C :
- (void)pushAddItemEventWithItem:(XYZItem *)item editMode:(XYZEditMode)editMode { NSString *editModeString = [self nameForEditMode:editMode]; [self pushToDataLayer:@{ @"event" : @"addItem", @"itemIdentifier" : item.identifier, @"editMode" : editModeString }]; }
這樣作有一個額外的好處:在有必要時,能夠清除掉整個統計分析框架,而 App 其他的部分不受任何影響。
首先應該讓 App 把崩潰日誌發送到某個服務器上,這樣你才能看獲得。可使用 PLCrashReporter結合本身的後臺實現這個功能,但推薦使用已有的第三方服務,好比下面這些:
設置好這些以後,每次發佈都要確保保存了 Xcode archive(.xcarchive).Archive 裏包含編譯出的二進制文件以及 Debug symbol( dSYM ),你須要這些數據來解析這個版本 App 的崩潰報告。
即便最簡單的 App 也有不一樣的構建方式。 Xcode 提供的最基本的區別是Debug和Release模式。後者的編譯時優化要強不少,代價是損失了 Debug 的可能性。蘋果建議你開發時使用 Debug模式,提交到 AppStore 的包用 Release模式編譯。默認的模式(在 Xcode 裏的運行/中止按鈕旁邊的下拉菜單能夠更改)就是這麼設置的,Run 用 Debug, Archive 用 Release。
不過對於真實的應用,這樣仍是過於簡單。你能夠--- 不!是應該 --- 有幾套不一樣的環境,分別用於測試、更新和其餘與服務相關的操做。每套環境均可以有本身的 base URL、log 級別、bundle identifier (這樣就能夠同時安裝)、provision profile 等。所以,簡單的 Debug/Release 不能知足需求。你能夠在 Xcode 工程設置的 "Info" 一欄裏添加更多的編譯配置。
編譯配置通常是在 Xcode 的界面裏設置的,不過你也可使用配置文件(".xcconfig 文件")來設置。這樣作的好處是:
#include
其餘編譯文件,幫助避免重複:
Common.xcconfig
文件,而後把它 #include
到其餘文件裏;#include "MyApp_Debug.xcconfig"
,而後覆蓋相應的設置更多關於本話題的信息,能夠參考這些幻燈片。
Targets 的概念比 project 低一個級別,即一個 project 能夠有多個 targets,這些 targets 的設置 能夠覆蓋它的 project 的設置。粗略地說,每個 target 對應着代碼庫上下文中的一個 app。舉個栗子,你可能針對不一樣國家的 Appstore 有不一樣的 App (都是從同一個代碼庫編譯出來的)。每個 App 都須要 開發/staging(階段性成果)/發佈 的編譯配置,所以用編譯配置(build configurations)會比 target 更好一些。一個 App 對應只有一個 target 很是常見。
Schemes 告訴 Xcode 在 Run、Test、Profile、Analyze 和 Archive 時分別應該幹什麼。基本上,以上每一個操做的 Scheme 對應一個 target 和 一套編譯配置。你也能夠傳遞啓動參數,好比 App 運行的語言(對於測試本地化很方便)或者設置一些 Debug 用的診斷標記。
Scheme 推薦的命名方式是 MyApp(<language>) [Environment]
:
MyApp (English) [Development] MyApp (German) [Development] MyApp [Testing] MyApp [Staging] MyApp [AppStore]
大部分環境下,語言是不須要標明的,由於 App 有可能經過 Xcode 以外的途徑安裝,好比 TestFlight,這樣啓動參數就會被忽略,這種狀況下,只能手動設置設備語言來測試本地化。
將 app 安裝到 iOS 設備上並不簡單。那麼咱們在這裏會介紹幾個核心的概念,理解了這些概念會對你部署 app 有很大幫助。
只要你想把應用跑在真機上,你就須要在編譯時用一個 Apple 頒發的 證書來簽名。每個證書對應一對公鑰/私鑰,私鑰保存在你Mac的鑰匙串中。證書有兩種:
除了證書以外,還有 Provisioning profiles(配置文件),它是關聯證書與設備的一環。一樣有兩類,分別用於開發和發佈:
*
結尾,好比 "net.senink.*")。要把全部的證書和 profile 同步到你的設備上,在 Xcode 的 Preference 中的 Accounts裏添加你的 Apple ID,而後雙擊團隊(team)名稱。底部有一個刷新按鈕,但有時須要重啓 Xcode 才能正常刷新。
有時你須要 Debug 一個 provisioning 問題。好比,Xcode 可能拒絕把包安裝到設備上,由於設備不在(development 或 ad-hoc 的) profile 的設備列表上。這種狀況下,你可使用 CraigHockenberry 優秀的 Provisioning插件定位到~/Library/MobileDevice/Provisioning Profiles
中,選擇.mobileprovision
文件而後按空格鍵啓動 Finder 的快速搜索功能,它會展現出很是豐富的信息,包括:設備、受權、證書和 App ID 等。
iTunes Connect是蘋果 AppStore 上的 App 管理平臺。上傳一個包,Xcode 須要一個開發者帳戶的 Apple ID 來簽名。若是你有多個開發者帳戶,想要分別上傳他們的 App,可能遇到一些麻煩,由於不知道爲何 一個特定的 Apple ID只能與一個 iTunes Connect 帳戶相關聯。替代的方法是,爲每一個 iTunes Connect 帳戶都建立一個新的 Apple ID,而後使用 Application Loader 代替 Xcode 來上傳包。這樣就把打包簽名與上傳 .ipa
文件的過程解耦了。
上傳包以後,保持耐心,可能一個小時後這個版本的 App 纔會出如今 Builds 一欄,當它出現後,你能夠把它與 App 的版本信息關聯起來,而後提交審覈。
驗證 App 內購的收據時,請記得進行如下檢查:
設計你的 IAP 系統時,儘可能把售賣的內容存儲再 server 端,而後僅當收到有效的、經過以上全部檢查的收據後才把內容提供給 client 端。這樣的設計防止了常規的盜版機制,而且--- 既然驗證是在 server 端進行的 --- 你能夠利用 Apple 的 HTTP 收據驗證服務,而不是本身解析收據的 PKCS #7 / ASN.1
格式文件。
關於這個問題,更多的信息請參考Futurice blog:Validating in-app purchases in your iOS app
Futurice 署名 - 相同方式共享 4.0 國際許可協議(CC BY 4.0)
KevinHM,喜歡就 Follow 吧,更多精彩將分享給您!
文檔的翻譯也參考了iOS-good-practices-in-Chinese!