App Programming Guide for iOS讀書筆記

這是閱讀該指南的一些筆記,說(shuō)說(shuō)是筆記,其實(shí)就是把一些自己決定重要的知識(shí)給翻譯了一遍,因?yàn)橛⑽淖x著讀著就把前面的給忘了。。。所以就打算記錄一點(diǎn)。該文章會(huì)慢慢更新,這段時(shí)間打算將幾篇重要的指南都重新看一遍,每天都會(huì)更新這些筆記,英語(yǔ)不大好,可能有翻譯錯(cuò)誤的地方,請(qǐng)大家指出,謝謝!

APP狀態(tài)

在任何時(shí)間上,你的APP只有一個(gè)狀態(tài),看表Table 2-3.系統(tǒng)切換APP狀態(tài)來(lái)響應(yīng)系統(tǒng)事件.舉例,當(dāng)用戶按下Home鍵,一個(gè)電話打來(lái),或者其他中斷的行為,當(dāng)前運(yùn)行的APP改變狀態(tài)來(lái)響應(yīng).Figure 2-3 顯示一個(gè)APP改變狀態(tài)的路徑.

狀態(tài) 描述
沒(méi)有運(yùn)行 該APP沒(méi)有運(yùn)行或者正在運(yùn)行但被系統(tǒng)終止
不活躍的 該APP在前臺(tái)運(yùn)行,但沒(méi)有接受到事件,APP一般都處在這個(gè)狀態(tài)
活躍 該APP在前臺(tái)運(yùn)行并且接受事件,這是前臺(tái)運(yùn)行APP正常狀態(tài)
后臺(tái) 該APP在后臺(tái)且在執(zhí)行代碼,大部分APP在該狀態(tài)會(huì)停留一段事件
暫停 該APP在后臺(tái)且沒(méi)有執(zhí)行代碼,系統(tǒng)會(huì)自動(dòng)將APP設(shè)置到這個(gè)狀態(tài)并不會(huì)通知APP.暫停后,APP保留在內(nèi)存內(nèi)但不會(huì)執(zhí)行代碼.當(dāng)內(nèi)存低時(shí),系統(tǒng)會(huì)殺死APP來(lái)使前臺(tái)有更多內(nèi)存

大多數(shù)狀態(tài)的改變都伴隨著系統(tǒng)方法的調(diào)用。你可以在這些方法內(nèi)響應(yīng)狀態(tài)。

  • application:willFinishLaunchingWithOptions: 啟動(dòng)時(shí)執(zhí)行第一次代碼
  • application:didFinishLaunchingWithOptions:允許在程序顯示之前進(jìn)行最終的初始化
  • applicationDidBecomeActive: 即將成為前臺(tái)應(yīng)用
  • applicationWillResignActive: 過(guò)渡狀態(tài),即將不活躍
  • applicationDidEnterBackground: 正在后臺(tái)運(yùn)行,會(huì)隨時(shí)暫停
  • applicationWillEnterForeground: 應(yīng)用從后臺(tái)到前臺(tái),但不活躍
  • applicationWillTerminate: 應(yīng)用正在被終止,暫停不會(huì)調(diào)用這個(gè)方法

本節(jié)講了應(yīng)用各種運(yùn)行的狀態(tài)和appdelgate里一些方法具體是什么時(shí)候被調(diào)用的

APP終止

APP應(yīng)該隨時(shí)準(zhǔn)備被終止而不應(yīng)該等待保存用戶數(shù)據(jù)或者執(zhí)行關(guān)鍵任務(wù),系統(tǒng)發(fā)起的終止是APP生命周期里的一個(gè)正常環(huán)節(jié)。
如果APP正在后臺(tái)運(yùn)行且沒(méi)有暫停,系統(tǒng)會(huì)在應(yīng)用終止前調(diào)用applicationWillTerminate,如果系統(tǒng)重啟,不會(huì)調(diào)用這個(gè)方法

線程和并發(fā)

系統(tǒng)創(chuàng)建主要的線程,你也可以創(chuàng)建額外的線程。對(duì)于iOS APP,你應(yīng)該首選GCD,操作隊(duì)列和其他的異步接口而不是自己創(chuàng)建和管理線程,使用GCD可以讓你更好的專注于工作,讓系統(tǒng)去處理線程相關(guān)的事情。

在思考線程和并發(fā)時(shí),你應(yīng)該注意以下幾點(diǎn)

  • 包括視圖,核心動(dòng)畫,還有很多UIKit的類通常都運(yùn)行在主線程上,但也有例外,譬如圖像的操作就在后臺(tái)
  • 耗時(shí)操作應(yīng)該在后臺(tái)處理,包括網(wǎng)絡(luò)請(qǐng)求,文件訪問(wèn)或者大量的數(shù)據(jù)處理都應(yīng)該使用異步的GCD或者操作隊(duì)列管理。
  • 在啟動(dòng)時(shí),應(yīng)該盡快的顯示界面,除了必須的建立視圖的操作,其他的耗時(shí)操作都應(yīng)該放在后臺(tái)

更多的GCD或者操作隊(duì)列信息請(qǐng)看 Concurrency Programming Guide

本節(jié)講了耗時(shí)操作能放在子線程就丟到子線程,除了創(chuàng)建視圖,刷新視圖等等。。

Strategies for Handling App State Transitions

可以在UIApplicationDelegate協(xié)議方法里面知道狀態(tài)改變。

What to Do at Launch Time

當(dāng)APP啟動(dòng)時(shí)(無(wú)論是前臺(tái)還是后臺(tái)),在application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:方法內(nèi)做以下幾點(diǎn):

  • 檢查Info.plist文件
  • 初始化關(guān)鍵數(shù)據(jù)
  • 準(zhǔn)備顯示視圖
    • OpenGL ES應(yīng)該在applicationDidBecomeActive:方法內(nèi)繪制
    • 顯示窗口在application:willFinishLaunchingWithOptions:方法內(nèi),顯示視圖在application:didFinishLaunchingWithOptions:方法內(nèi)

在啟動(dòng)時(shí)候要盡快完成,超過(guò)5秒系統(tǒng)會(huì)自動(dòng)殺死該進(jìn)程。

The Launch Cycle

應(yīng)用進(jìn)入運(yùn)行狀態(tài)流程圖

應(yīng)用在后臺(tái)會(huì)處理事件,并會(huì)在某個(gè)時(shí)間點(diǎn)暫停。它仍會(huì)加載界面文件但不會(huì)顯示

可以通過(guò)applicationState屬性區(qū)別當(dāng)前應(yīng)用狀態(tài),在前臺(tái)時(shí)為UIApplicationStateInactive,后臺(tái)時(shí)為UIApplicationStateBackground

Launching in Landscape Mode

應(yīng)用必須設(shè)置朝向,如果支持橫向和縱向,那么默認(rèn)是縱向。如果只支持橫向,需要做到以下幾點(diǎn):

  • 在info.plist文件中添加UIInterfaceOrientationKey值,設(shè)置屬性為UIInterfaceOrientationLandscapeLeft或者 UIInterfaceOrientationLandscapeRight.
  • 確保約束是正確的

What to Do When Your App Is Interrupted Temporarily

當(dāng)應(yīng)用暫時(shí)中斷時(shí),系統(tǒng)仍在前臺(tái)但是不能接受觸摸事件,但可以接受類似陀螺儀事件,你需要在applicationWillResignActive:方法內(nèi)做以下操作:

  • 保存數(shù)據(jù)或者關(guān)鍵信息
  • 停止定時(shí)器或者其他周期性任務(wù)
  • 停止數(shù)據(jù)查詢
  • 不初始化新的任務(wù)
  • 停止視頻(除了AirPlay)
  • 停止游戲
  • 終止GCD或者操作隊(duì)列

在應(yīng)用進(jìn)入活躍狀態(tài)時(shí),在applicationWillResignActive方法內(nèi)你應(yīng)該重啟定時(shí)器,恢復(fù)隊(duì)列。游戲不應(yīng)該恢復(fù),這應(yīng)該讓用戶手動(dòng)開始。

Responding to Temporary Interruptions

假如有電話打來(lái),應(yīng)用會(huì)進(jìn)入inactive狀態(tài),直到用戶結(jié)束通話,應(yīng)用回到活躍狀態(tài)或者后臺(tái)。

用戶拉下通知橫幅會(huì)造成應(yīng)用進(jìn)入inactive狀態(tài)。
用戶按下鎖屏鍵,系統(tǒng)禁用觸摸事件并且使應(yīng)用進(jìn)入后臺(tái),這時(shí)候數(shù)據(jù)文件會(huì)被加密保護(hù)起來(lái)。

What to Do When Your App Enters the Foreground

當(dāng)應(yīng)用進(jìn)入前臺(tái)狀態(tài)時(shí),applicationWillEnterForeground:方法會(huì)撤銷所有applicationDidEnterBackground:方法里的事情,并在applicationDidBecomeActive:方法里做激活任務(wù)。

UIApplicationWillEnterForegroundNotification這個(gè)枚舉也可以用來(lái)監(jiān)聽?wèi)?yīng)用進(jìn)入前臺(tái)狀態(tài)。

Be Prepared to Process Queued Notifications

Event Notifications
配件斷開或鏈接 EAAccessoryDidConnectNotification
屏幕旋轉(zhuǎn) UIDeviceOrientationDidChangeNotification
完整一天過(guò)去 UIApplicationSignificantTimeChangeNotification
偏好設(shè)置改變 NSUserDefaultsDidChangeNotification
語(yǔ)言改變或者區(qū)域改變 NSCurrentLocaleDidChangeNotification

應(yīng)用在后臺(tái)時(shí)仍然能調(diào)用setNeedsDisplay或者setNeedsDisplayInRect:,但是因?yàn)橐晥D是不顯示的,所以會(huì)在下次應(yīng)用進(jìn)入前臺(tái)時(shí)更新視圖。

What to Do When Your App Enters the Background

從前臺(tái)進(jìn)入后臺(tái),在applicationDidEnterBackground:方法里做以下幾點(diǎn):

  • 給你應(yīng)用準(zhǔn)備一張圖片。如果用戶退出前臺(tái)前的那個(gè)頁(yè)面包含了敏感信息,你應(yīng)該隱藏或者修改這張圖片在applicationDidEnterBackground:方法返回前。
  • 保存有關(guān)應(yīng)用的狀態(tài)信息
  • 釋放不需要的內(nèi)存。因?yàn)橄到y(tǒng)會(huì)殺掉占用內(nèi)存大的應(yīng)用,所以應(yīng)該讓你的應(yīng)用在進(jìn)入后臺(tái)前釋放圖片資源,緩存和一些不需要的數(shù)據(jù)。

應(yīng)用在applicationDidEnterBackground:方法里大概有5秒的時(shí)間來(lái)完成任務(wù)。實(shí)際上,這個(gè)方法應(yīng)該盡可能快的返回。如果方法沒(méi)有在時(shí)間耗盡前返回,系統(tǒng)會(huì)殺掉應(yīng)用并釋放內(nèi)存。如果你需要長(zhǎng)時(shí)間進(jìn)行任務(wù),你應(yīng)該在beginBackgroundTaskWithExpirationHandler:方法里進(jìn)行,并且在secondary線程上。不管你在applicationDidEnterBackground:方法內(nèi)進(jìn)行任何操作都必須在5秒內(nèi)返回。

Note:UIApplicationDidEnterBackgroundNotification這個(gè)枚舉可以知道系統(tǒng)進(jìn)入后臺(tái)

The Background Transition Cycle

當(dāng)用戶按下Home鍵,關(guān)機(jī)鍵或者打開其他應(yīng)用,前臺(tái)應(yīng)用會(huì)變到inactive狀態(tài)然后到background狀態(tài)。這些轉(zhuǎn)變結(jié)果會(huì)調(diào)用到applicationWillResignActive:applicationDidEnterBackground:方法。在applicationDidEnterBackground:方法返回后,大多數(shù)應(yīng)用會(huì)在不久后變到suspended狀態(tài)。如果應(yīng)用需要特殊的后臺(tái)任務(wù)(像播放音樂(lè))或者執(zhí)行額外的長(zhǎng)時(shí)間任務(wù),background狀態(tài)會(huì)延長(zhǎng)。

Prepare for the App Snapshot

applicationDidEnterBackground:方法返回不久后,系統(tǒng)會(huì)生成一張應(yīng)用快照用于顯示。同樣,當(dāng)應(yīng)用被喚醒來(lái)處理一些后臺(tái)任務(wù),系統(tǒng)也許需要生成一張新的快照來(lái)反映改變。

如果你想對(duì)顯示的快照做更改,你需要調(diào)用snapshotViewAfterScreenUpdates:來(lái)更新視圖,這個(gè)方法能馬上更新視圖,調(diào)用setNeedsDisplay方法是沒(méi)用的,這個(gè)上面文檔講過(guò)了。


Strategies for Implementing Specific App Features

不同的應(yīng)用有不同的需要,但是有些行為應(yīng)該是相同的。下面的章節(jié)會(huì)介紹這些特定的功能如何實(shí)現(xiàn)。

Privacy Strategies

保護(hù)用戶隱私對(duì)于應(yīng)用來(lái)說(shuō)是很重要的。系統(tǒng)已經(jīng)提供了保護(hù)隱私的方法。

Protecting Data Using On-Disk Encryption

設(shè)備鎖屏以后,是不能訪問(wèn)被保護(hù)的文件的,就算文件是應(yīng)用創(chuàng)建的也不可以。想訪問(wèn)保護(hù)文件必須在設(shè)備解鎖之后。

數(shù)據(jù)保護(hù)在大部分設(shè)備上是可用的,只需要遵循以下幾點(diǎn):

  • 文件系統(tǒng)必須支持?jǐn)?shù)據(jù)保護(hù),這在大部分設(shè)備上是可行的
  • 用戶必須設(shè)置密碼鎖

使用NSDataNSFileManager類可以通過(guò)添加屬性來(lái)設(shè)置保護(hù)等級(jí)。當(dāng)寫入新文件時(shí),你可以使用NSDatawriteToFile:options:error:方法。對(duì)于已存在的文件,你可以使用NSFileManagersetAttributes:ofItemAtPath:error:方法,使用這些方法,你可以設(shè)置以下幾個(gè)保護(hù)等級(jí):

  • No protection -> 文件被加密但是當(dāng)設(shè)備被鎖屏?xí)r不能被密碼保護(hù)。選擇NSDataWritingFileProtectionNone這個(gè)枚舉。
  • Complete -> 文件被加密且不能被訪問(wèn)當(dāng)設(shè)備被鎖屏。選擇NSDataWritingFileProtectionComplete枚舉。
  • Complete unless already open -> 文件被加密且不能被訪問(wèn)當(dāng)設(shè)備被鎖屏,當(dāng)文件被訪問(wèn)時(shí)設(shè)備鎖屏,應(yīng)用仍然可以在鎖屏狀態(tài)下訪問(wèn)文件。選擇NSDataWritingFileProtectionCompleteUnlessOpen枚舉
  • Complete until first login -> 文件被加密且不能訪問(wèn)直到設(shè)備啟動(dòng),用戶解鎖一次。

如果你保護(hù)了文件,那么應(yīng)用會(huì)隨時(shí)不能訪問(wèn)文件。當(dāng)設(shè)備鎖屏?xí)r,你可以通過(guò)幾點(diǎn)知道是否可以訪問(wèn)文件:

  • 可以在app delegate里實(shí)現(xiàn)applicationProtectedDataWillBecomeUnavailable:applicationProtectedDataDidBecomeAvailable:方法
  • 任何對(duì)象都可以注冊(cè)UIApplicationProtectedDataWillBecomeUnavailableUIApplicationProtectedDataDidBecomeAvailable通知
  • 可以通過(guò)UIApplicationprotectedDataAvailable屬性來(lái)知道當(dāng)前是否可以訪問(wèn)文件

反正就是推薦文件保護(hù)。

Identifying Unique Users of Your App

你應(yīng)該區(qū)別每一個(gè)用戶,并且這一行為應(yīng)該是透明的。

在以下幾種情況下,也許你需要這樣做

  • 登錄
  • 給不同的用戶觀看不同的廣告

如果你需要在不同設(shè)備上辨認(rèn)是否是一個(gè)用戶,你需要提供自己的一套識(shí)別系統(tǒng)。

Supporting Multiple Versions of iOS

一個(gè)在多個(gè)版本運(yùn)行的應(yīng)用應(yīng)該檢查系統(tǒng)版本,防止在舊系統(tǒng)上使用了新系統(tǒng)的API。

有幾個(gè)檢查方法你可以選擇:

  • 確定這個(gè)類是否存在
if ([UIPrintInteractionController class]) {
   // Create an instance of the class and use it.
}
else {
   // The print interaction controller is not available so use an alternative technique.
}
  • 判斷一個(gè)類是否可以使用這個(gè)方法,通過(guò)instancesRespondToSelector:類方法或者respondsToSelector:實(shí)例方法。
  • 判斷基于C語(yǔ)言的函數(shù)是否可用
if (UIGraphicsBeginPDFPage != NULL) {
    UIGraphicsBeginPDFPage();
}

想知道這方面更多的知識(shí),可以看 SDK Compatibility Guide.

Preserving Your App’s Visual Appearance Across Launches

Enabling State Preservation and Restoration in Your App

狀態(tài)保存和恢復(fù)不是自動(dòng)的,系統(tǒng)必須選擇使用。如果要使用這些功能,需要實(shí)現(xiàn)以下方法
application:shouldSaveApplicationState:,application:shouldRestoreApplicationState:

一般來(lái)說(shuō),返回YES是表明功能可用。但是有些時(shí)候需要返回NO,比如應(yīng)用更新了,你不應(yīng)該恢復(fù)舊的頁(yè)面。

The Preservation and Restoration Process

在保存和恢復(fù)過(guò)程中,應(yīng)用也有少量的任務(wù):

  • 保存過(guò)程
    • 告訴UIKit支持保存
    • 告訴UIKit什么控制器和視圖需要被保存
    • 給保存的對(duì)象編碼
  • 恢復(fù)過(guò)程
    • 告訴UIKit支持恢復(fù)
    • 提供需要的UIKit對(duì)象
    • 讓保存的對(duì)象恢復(fù)原樣

Figure 5-1 顯示了簡(jiǎn)單的視圖控制器的層次結(jié)構(gòu)。如果沒(méi)有狀態(tài)恢復(fù),只有main storyboard文件里的控制器在隨后的啟動(dòng)中恢復(fù)。當(dāng)你的應(yīng)用支持狀態(tài)恢復(fù),你可以保存所有的控制器

UIKit保存對(duì)象需要一個(gè)保存identifier,假如控制器沒(méi)有這個(gè)identifier,他和他的子視圖都不會(huì)被保存。Figure 5-2 展示了部分擁有identifier的控制器

這些功能對(duì)于應(yīng)用來(lái)說(shuō)也許是毫無(wú)意思的,因?yàn)閁IKit本身就能簡(jiǎn)單的保存和恢復(fù)。

對(duì)于你保存的所有控制器 ,你也需要決定如果去恢復(fù)它們。UIKit 提供了兩種方式去創(chuàng)建對(duì)象。你可以去重新創(chuàng)建它們或者通過(guò) view controller 去恢復(fù)它們。restoration class實(shí)現(xiàn)UIViewControllerRestoration協(xié)議,并且在恢復(fù)的時(shí)候去負(fù)責(zé)尋找或者創(chuàng)建指定的對(duì)象。這里有幾個(gè)建議:

  • 如果你的控制器是通過(guò) main storyboard 文件加載的,就不用這樣搞了,讓UIKit自己去恢復(fù)吧
  • 如果不是第一種情況,那么最簡(jiǎn)單恢復(fù)辦法就是讓每一個(gè)控制器都實(shí)現(xiàn)協(xié)議。

在保存過(guò)程中,UIKit 保存對(duì)象并且寫入到磁盤。每個(gè)控制器也有一次機(jī)會(huì)來(lái)保存數(shù)據(jù)。

Flow of the Preservation Process

Figure 5-3 展示了直到保存狀態(tài)前的高級(jí)事件和應(yīng)用是如何被影響的。在保存之前,UIKit 會(huì)調(diào)用application:shouldSaveApplicationState:方法,如果返回YES的話會(huì)開始保存視圖。

下次應(yīng)用啟動(dòng)的時(shí)候會(huì)自動(dòng)尋找保存狀態(tài)的文件,如果有的話就恢復(fù)。因?yàn)檫@些文件只適用于上次和當(dāng)前的周期,在啟動(dòng)后會(huì)刪除上次的保存狀態(tài)文件。在恢復(fù)過(guò)程中有錯(cuò)誤也會(huì)刪除保存狀態(tài)文件。舉例,在一次恢復(fù)過(guò)程中應(yīng)用崩潰了,那么系統(tǒng)會(huì)自動(dòng)刪除文件防止下次恢復(fù)再崩潰。

What Happens When You Exclude Groups of View Controllers?

Figure 5-5 展示了當(dāng)導(dǎo)航控制器沒(méi)有保存identifier,他的子控制器和視圖都不會(huì)被保存

即使你不保存控制器,也不意味著所有控制器從視圖層次中消失了。舉個(gè)例子,如果有控制器是從 storyboard 文件中加載的,他會(huì)一直顯示。

Checklist for Implementing State Preservation and Restoration

你如果想通過(guò)代碼來(lái)實(shí)現(xiàn)保存和恢復(fù)狀態(tài),你應(yīng)該看看以下幾點(diǎn):

  • 實(shí)現(xiàn)application:shouldSaveApplicationState:application:shouldRestoreApplicationState:方法
  • 給你想要保存的控制器添加非空字符串的restorationIdentifier屬性
  • application:willFinishLaunchingWithOptions:展示窗口
  • 給適當(dāng)?shù)目刂破髦付?restoration classes
  • 使用encodeRestorableStateWithCoder:decodeRestorableStateWithCoder:編碼解碼控制器狀態(tài)
  • 編碼解碼任意的版本信息或者狀態(tài)信息使用application:willEncodeRestorableStateWithCoder:application:didDecodeRestorableStateWithCoder:方法
  • 數(shù)據(jù)源實(shí)現(xiàn)UIDataSourceModelAssociation協(xié)議,雖然這不是必須的,但是這個(gè)協(xié)議可以幫助我們保存選中的和可見的視圖

Preserving the State of Your View Controllers

保存單獨(dú)的控制器狀態(tài),你需要做到以下幾點(diǎn):

  • 必須有 restoration identifier
  • 必須在啟動(dòng)的時(shí)候創(chuàng)建或者找到新的控制器
  • 可選的來(lái)實(shí)現(xiàn)encodeRestorableStateWithCoder:decodeRestorableStateWithCoder:方法

Marking Your View Controllers for Preservation

UIKit 只會(huì)恢復(fù)擁有有效 restorationIdentifier 的對(duì)象。

恢復(fù)路徑是從上往下。

Restoring Your View Controllers at Launch Time

在恢復(fù)過(guò)程中,UIKit 會(huì)通過(guò)幾種辦法去恢復(fù):

  • 如果控制器有 restoration class ,那么 UIKit 會(huì)去恢復(fù)控制器。調(diào)用viewControllerWithRestorationIdentifierPath:coder:方法,如果返回nil的話就代表不想創(chuàng)建控制器,UIKit 會(huì)放棄尋找。
  • 如果控制器沒(méi)有 restoration class ,UIKit 會(huì)讓 app delegate 去恢復(fù)控制器。調(diào)用application:viewControllerWithRestorationIdentifierPath:coder:
  • 如果控制器已經(jīng)存在正確的恢復(fù)路徑,UIKit 會(huì)使用這個(gè)對(duì)象
  • 如果控制器是通過(guò) storyboard 去加載的,UIKit 會(huì)通過(guò) storyboard 去尋找和創(chuàng)建控制器。

以下代碼展示了如果在恢復(fù)過(guò)程中創(chuàng)建控制器。

+ (UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
                      coder:(NSCoder *)coder {
   MyViewController* vc;
   UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
   if (sb) {
      vc = (PushViewController*)[sb instantiateViewControllerWithIdentifier:@"MyViewController"];
      vc.restorationIdentifier = [identifierComponents lastObject];
      vc.restorationClass = [MyViewController class];
   }
    return vc;
}

Inter-App Communication

應(yīng)用之間可以通過(guò) URL 來(lái)進(jìn)行通信。

Supporting AirDrop

AirDrop 可以發(fā)送圖片,文件,URLs,和其他類型的數(shù)據(jù)給附近的設(shè)備。AirDrop 通過(guò) peer-to-peer 網(wǎng)絡(luò)來(lái)尋找附近的設(shè)備。

Sending Files and Data to Another App

如果想通過(guò) AirDrop 發(fā)送文件和數(shù)據(jù),使用UIActivityViewController對(duì)象。當(dāng)你創(chuàng)建了這個(gè)控制器,
你可以指定你想顯示什么。你也可以顯示自定義對(duì)象,只要遵守UIActivityItemSource協(xié)議。

你可以通過(guò)excludedActivityTypes屬性來(lái)指定不顯示的類型。當(dāng)顯示一個(gè) activity view controller 在iPad上時(shí),你必須使用popover。

在iPhone上顯示 activity view controller

- (void)displayActivityControllerWithDataObject:(id)obj {

   UIActivityViewController* vc = [[UIActivityViewController alloc]

                                initWithActivityItems:@[obj] applicationActivities:nil];

    [self presentViewController:vc animated:YES completion:nil];
}

Receiving Files and Data Sent to Your App

使用 AirDrop 接受文件你需要注意以下幾點(diǎn):

  • 在 Xcode 里,聲明你的應(yīng)用能打開的文件
  • 在 app delegate 里,實(shí)現(xiàn)application:openURL:sourceApplication:annotation:方法來(lái)接受數(shù)據(jù)
  • 在 Documents/Inbox 里查看文件,如果需要的話把文件移出來(lái)(需要修改的話)

傳輸?shù)?Documents/Inbox 中的文件你只能讀取或者刪除,但不能修改

Using URL Schemes to Communicate with Apps

Apple 內(nèi)置了很多 URL schemes。如果你的 URL 定義了一個(gè)和 Apple 相同的東西,那么在你應(yīng)用啟動(dòng)時(shí)會(huì)打開 Apple 的應(yīng)用。

Sending a URL to Another App

當(dāng)你實(shí)現(xiàn)自定義的 URL scheme 來(lái)發(fā)送數(shù)據(jù)給別的應(yīng)用,調(diào)用openURL:方法。

以下代碼展示了一個(gè)應(yīng)用如何打開另一個(gè)應(yīng)用

NSURL *myURL = [NSURL URLWithString:@"todolist://www.acme.com?Quarterly%20Report#200806231300"];

[[UIApplication sharedApplication] openURL:myURL];

如果應(yīng)用自定義了一個(gè) URL scheme ,請(qǐng)看Implementing Custom URL Schemes

PS: iOS9新增了一個(gè)白名單,蘋果規(guī)定開發(fā)者只能設(shè)置50個(gè) URL scheme 來(lái)打開別的應(yīng)用,在openURL:之前還需要做個(gè)判斷canOpenURL:,返回到前一個(gè)應(yīng)用不用這樣做。

Implementing Custom URL Schemes

如果你的應(yīng)用可以接收特定的 URLs,你應(yīng)該在系統(tǒng)里注冊(cè)相應(yīng)的 URL schemes。

Registering Custom URL Schemes

在應(yīng)用里注冊(cè) URL 類型,你應(yīng)該在 Info.plist 文件中加入CFBundleURLTypes key。這個(gè) key 包含一個(gè)字典數(shù)組,每一個(gè)都定義了一個(gè) URL schemes。

Key Value
CFBundleURLName 字符串包含了一個(gè) URL scheme。為了確保唯一性,推薦指定一個(gè)反向域名格式的標(biāo)識(shí),舉個(gè)例子, com.acme.myscheme。
CFBundleURLSchemes 字符串?dāng)?shù)組包含了 URL scheme 名字,舉個(gè)例子,http, mailto, tel, 和 sms。

Note: 如果多個(gè)第三方應(yīng)用使用了相同的 URL scheme,目前還沒(méi)有好的辦法來(lái)解決。

Handling URL Requests

每個(gè)應(yīng)用都有自己自定義的 URL scheme 并且也該知道如何去處理它們。你應(yīng)該在 delegate 中實(shí)現(xiàn)以下方法:

  • 使用application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:方法來(lái)檢查 URL 的信息并決定是否打開。如果其中一個(gè)方法返回 NO,你應(yīng)用處理 URL 的代碼不會(huì)被調(diào)用。
  • 使用application:openURL:sourceApplication:annotation:方法來(lái)打開文件。(iOS9廢棄了,應(yīng)該使用application:openURL:options:

Figure 6-1 展示了在一個(gè)要求打開網(wǎng)址的應(yīng)用上顯示修改好的啟動(dòng)順序

Figure 6-2 展示了切換到前臺(tái)狀態(tài)打開 URL

Displaying a Custom Launch Image When a URL is Opened

應(yīng)用支持自定義的 URL schemes 可以提供自定義的啟動(dòng)圖片。當(dāng)系統(tǒng)啟動(dòng)你的應(yīng)用通過(guò) URL 時(shí)并沒(méi)有有效的快照,他會(huì)顯示你指定的啟動(dòng)圖片。指定一個(gè)啟動(dòng)圖片,提供一張使用以下名字格式的 PNG 圖片:

basename代表了基本的圖片名字,假如名字是 Default,url_scheme 是你的 URL scheme 的一部分名字,假如 URL scheme 是 myapp,那么你的啟動(dòng)圖片名字就是 Default-myapp@2x.png。


Performance Tips

本章講述整體性能的幾點(diǎn)。

Reduce Your App’s Power Consumption

功耗始終是移動(dòng)設(shè)備上的一個(gè)大問(wèn)題。你可以通過(guò)優(yōu)化以下幾個(gè)功能來(lái)提高電池壽命:

  • CPU
  • WiFi,藍(lán)牙,基帶
  • 定位
  • 加速劑
  • 訪問(wèn)硬盤

你應(yīng)該經(jīng)常使用 Instruments 來(lái)優(yōu)化算法。但是即使最優(yōu)算法也會(huì)對(duì)電池壽命有意向。你應(yīng)該在寫代碼的時(shí)候注意以下幾點(diǎn):

  • 避免使用 polling。polling 不會(huì)讓 CPU 進(jìn)入休眠。應(yīng)該使用NSRunLoop或者NSTime代替。
  • 設(shè)置idleTimerDisabled屬性為 NO,這個(gè)屬性默認(rèn)就是 NO,當(dāng)用戶不再輸入時(shí)會(huì)關(guān)閉屏幕。如果你需要屏幕不被關(guān)閉,你應(yīng)該修改代碼而不是設(shè)置屬性為 YES。
  • 盡可能的合并一些任務(wù)來(lái)增加 CPU 空閑時(shí)間。因?yàn)橐恍┖苄〉娜蝿?wù)常常會(huì)喚醒 CPU。
  • 避免經(jīng)常訪問(wèn)硬盤。
  • 需要多少內(nèi)容繪制多少內(nèi)容。繪制很耗電,不要依靠硬件來(lái)控制幀數(shù),應(yīng)該是內(nèi)容需要幾幀繪制幾幀。
  • 如果你使用UIAccelerometer來(lái)接收加速計(jì)時(shí)間。PS:看了下好像這個(gè)類在5.0就廢棄了。

訪問(wèn)網(wǎng)絡(luò)數(shù)據(jù)是很耗電的,通過(guò)以下幾點(diǎn)來(lái)使訪問(wèn)數(shù)據(jù)次數(shù)最小化:

  • 僅在需要的時(shí)候訪問(wèn)網(wǎng)絡(luò)并且不 poll 服務(wù)。
  • 當(dāng)你必須訪問(wèn)網(wǎng)絡(luò)時(shí),發(fā)送最少的數(shù)據(jù)量。
  • 發(fā)送數(shù)據(jù)而不是發(fā)送數(shù)據(jù)包。系統(tǒng)會(huì)在空閑的時(shí)候關(guān)閉 WiFi 和 無(wú)線電。當(dāng)你使用NSURLSession來(lái)進(jìn)行多個(gè)上傳或下載任務(wù)時(shí),應(yīng)該讓他們同時(shí)進(jìn)行而不是一個(gè)個(gè)來(lái)。系統(tǒng)會(huì)自動(dòng)管理隊(duì)列。
  • 盡可能的使用WiFi來(lái)訪問(wèn)網(wǎng)絡(luò)。
  • 如果使用定位,你應(yīng)該使用最適合的 distance filter 和精確度

Instruments 應(yīng)用包含了幾個(gè)收集電池信息的 Instruments。還可以收集指定硬件耗電量。你也可以使用診斷記錄來(lái)收集信息。PS:這個(gè)在手機(jī)設(shè)置里可以看。

Use Memory Efficiently

系統(tǒng)的可用內(nèi)存會(huì)影響應(yīng)用的性能。

Observe Low-Memory Warnings

系統(tǒng)發(fā)出內(nèi)存警告時(shí)應(yīng)該移除不需要的對(duì)象。回應(yīng)這個(gè)警告是很重要的否則系統(tǒng)可能會(huì)終止應(yīng)用。系統(tǒng)通過(guò)以下幾個(gè) API 來(lái)發(fā)送內(nèi)存警告:

  • app delegate 的applicationDidReceiveMemoryWarning:
  • UIViewControllerdidReceiveMemoryWarning
  • UIApplicationDidReceiveMemoryWarningNotificationnotification通知
  • GCD 的DISPATCH_SOURCE_TYPE_MEMORYPRESSURE類型。這是你唯一能用來(lái)辨別內(nèi)存壓力大不大。

收到內(nèi)存警告你應(yīng)該釋放掉不需要的內(nèi)存。例如清理緩存,釋放圖片。如果你有一個(gè)不用的大數(shù)據(jù),應(yīng)該把它寫進(jìn)磁盤。

你可以通過(guò)UIApplicationDidReceiveMemoryWarningNotification通知來(lái)直接刪除不需要的資源。

Reduce Your App’s Memory Footprint

Table 7-1 減少應(yīng)用內(nèi)存占用空間

Tip Actions to take
清楚內(nèi)存泄露 在iOS中內(nèi)存是很關(guān)鍵的資源,你的應(yīng)用不應(yīng)該有內(nèi)存泄露。使用 Instruments 查看是否有內(nèi)存泄露。
資源文件盡可能的小 文件寫入到磁盤之前會(huì)在內(nèi)存中存在。盡可能的壓縮圖片文件(PNG 圖片是 iOS 首選的圖片格式)。
懶加載資源 在需要使用要資源時(shí)再加載。

后面這些很多都在之前的文檔有講到,感興趣的朋友可以自己去翻閱一下。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容