簡介
NSBundleResourceRequest按需加載資源是iOS9.0之后新增的類,按需加載資源是由App Store托管的內容,它和下載的app bundle是分開的。app請求一系列按需加載資源,而下載和存儲資源是由操作系統(tǒng)來管理。這些資源可以是除可執(zhí)行代碼外,bundle支持的任何類型。支持類型的完整列表,請參閱附錄a:按需加載的資源類型。
按需加載資源主要可以帶來以下的幾種好處:
- 初始資源的延遲加載。app有一些資源是主要功能要用到的,但在啟動時并不需要。將這些資源標記為“初始需要”。操作系統(tǒng)在app啟動時會自動下載這些資源。例如,圖片編輯app有許多不常用的濾鏡。
- app資源的延遲加載。app有一些只在特定情景下使用的資源,當應用可能要進入這些場景時,會請求這些資源。例如,在一個有很多關卡的游戲中,用戶只需要當前關卡和下一關卡的資源。
- 不常用資源的遠程存儲。app有一些很少使用的資源,當需要這些資源時會去請求它們。例如,當app第一次打開時會展示一個教程,而這個教程之后就可能不會在用到。app在第一次啟動時請求教程的資源,這之后只在需要展示教程或者添加了新功能才去請求該資源。
- 應用內購買資源的遠程存儲。app提供包含額外資源的應用內購買。app會在啟動完成后請求已購買模塊的資源。例如,用戶在一個鍵盤app內購買了SuperGeeky表情包。應用程序會在啟動完成后請求表情包的資源。
- 第一次啟動時必需資源的加載。app有一些資源只在第一次啟動時需要,之后的啟動不再需要。例如,app有一個只在第一次啟動時展示的教程。
在開發(fā)時,通過給按需加載資源分配一個或多個tag來區(qū)分。tag是一個你創(chuàng)建的字符串標識符。你可以使用tag的名稱來區(qū)分這些資源在你的app中是如何使用的。例如,在一個游戲中,所有第五關的資源可以使用tag level-5
。
在運行時,你通過指定tag來請求訪問遠程資源。操作系統(tǒng)會下載和這個tag關聯(lián)的所有資源,然后保留在存儲中,直到app不再使用它們。當操作系統(tǒng)需要更多的存儲空間,它會清理一個或多個不再使用的tag關聯(lián)的資源。tag關聯(lián)的資源在被清理之前可能會在設備中保存一段時間。
繼續(xù)上面游戲的例子,游戲有許多關卡,用戶只需要當前正在玩的關卡和可能玩的下一關卡的資源。下圖的上部展示了包括全部關卡資源的app bundle??梢酝ㄟ^為不同關卡和其他無需放在app內的資源,創(chuàng)建不同tag的按需加載資源,來縮減app bundle的大小。下圖的底部顯示了一個更小的app,其中加了tag的資源由App Store托管。
還有一些其他的功能,比如讓你指定那些在app啟動之前必須加載的資源,為資源請求設置優(yōu)先級,追蹤資源下載的進度,為不再使用的已下載tag設置保留優(yōu)先級。
按需加載資源的生命周期
當用戶第一次啟動app時,設備上唯一的按需加載資源是那些設置為預獲取的。隨著用戶使用app,app會請求加了tag的資源,使用這些資源,然后告訴操作系統(tǒng)不再使用這些資源了。在這之后的某個時間,操作系統(tǒng)會清理一個或多個tag。
注意:app應該請求tag,而不是單個資源。
當你在開發(fā)按需加載資源時,可能會注意到請求下載某個tag時,其他tag也會被下載。這是因為操作系統(tǒng)處理的是資源包(asset pack),這些資源包會為共享資源的下載進行優(yōu)化。一個tag可能對應多個資源包。資源包是在構建app時由Xcode生成的。
加了tag的資源的生命周期如下所示:
1、加了tag的資源由App Store托管。
這發(fā)生在app第一次啟動和之前加載的tag被清理時。
2、加tag的資源被下載到設備上
這發(fā)生在app請求一個設備上沒有的tag之后,或者發(fā)生在操作系統(tǒng)下載初始資源。
下圖中展示的是,app請求Level11
和Forest
tag關聯(lián)的資源,然后下載到設備上。
3、操作系統(tǒng)將tag保存在本地存儲中,并通知app這些tag已經可以使用。
這發(fā)生在一個tag下的所有資源都已成功下載之后,或者tag對應的資源都已緩存在本地存儲中。
在tag可用之后,app就可以使用tag關聯(lián)的資源了。按需加載資源的使用方式和使用下載的app中資源包一樣。下圖展示了下載的資源就像是app的虛擬成員一樣。
4、操作系統(tǒng)釋放本地存儲中的tag。
被釋放的tag還會保存在設備中,直到它再次被請求,或者從本地存儲中被清理掉。當一個tag沒有被任何請求持有時,tag就可以被清理。在tag被清理之前,它還可能在設備上保存一段時間,包括app多次啟動。請求一個tag會持有該tag,然后返回上面的步驟3。
清理tag會返回到上面的步驟1。你可以為tag設置保存優(yōu)先級來影響清理的順序。更多信息參見管理按需加載資源。
啟用按需加載資源
對于支持iOS 9.0及以后的app,按需加載資源是默認開啟的。你也可以在target的build settings中手動更改。
啟用或關閉按需加載資源:
1、在project navigator中選擇工程文件。
2、在project editor中選擇對應的target。
3、選擇Build Settings選項卡。
4、展開Assets分類。
提示:可以在Build Settings選項卡右上角的搜索框中輸入“Assets”,來快速定位到Assets分類。
5、設置Enable On-Demand Resources的值。
Yes為這個target開啟按需加載資源。
No為這個target關閉按需加載資源。
創(chuàng)建和編輯tag
tag用來區(qū)分和管理按需加載資源。給一個資源添加一個或多個tag就能將其標記為按需加載資源。在運行時,所有管理按需加載資源的調用都是和tag相關,而不是單個資源。在運行時管理按需加載資源在管理按需加載資源中有講到。
Xcode中的資源 tag
Xcode提供了管理tag和相關資源的工具。包括創(chuàng)建和編輯tag,添加和刪除tag下的資源,指定操作系統(tǒng)在什么時刻下載tag關聯(lián)的資源。
Resource Tags選項卡
Resource Tags選項卡在project editor中,用來瀏覽和編輯工程中全部的tag和相關資源。選項卡包括:
添加按鈕:用來創(chuàng)建新的tag。
搜索框:用來查找指定的tag或資源。
tag編輯器:用來更改tag的名稱,刪除tag,增刪tag下的資源。tag下全部資源所占的存儲大小會顯示在tag名稱右邊的圓括號中。大小是依據最后一次構建所選擇的運行設備來計算的。
tag視圖選擇器:用來在查看全部tag和查看預獲取分類tag之間切換。tag可以在app安裝時下載,在安裝之后預獲取,或者在app運行時按需加載。預取優(yōu)先級編輯器也會顯示每個分類中資源所占的存儲大小。大小是依據最后一次構建所選擇的運行設備來計算的。
按需加載資源tag框
在按需加載資源tag框中,你可以快速瀏覽一個文件夾或資源,并為其添加刪除tag。在Asset Catalog中,如果文件夾或者某個類型的資源可以加tag的話,這個框顯示在Attributes inspector中,如下圖所示。
創(chuàng)建tag
創(chuàng)建tag的第一步是檢查你的app在運行時如何使用資源??纯茨愕腶pp是否有以下幾種資源:
在任何時刻都必須是app的一部分。
可以提升用戶體驗,但在啟動app時不是必需的。包括高分辨率素材、高質量聲音等等。
在特定場景下才需要。
上面說的后兩類的就有可能是按需加載資源。在app第一次啟動后馬上就要用到的資源可以設置為在安裝后自動預獲取。操作方法見預獲取tag。
每個tag下的資源總計大小不能超過2GB。按需加載資源的總計大小不能超過20GB。按需加載資源的大小是不算在app bundle的大小中的。更多信息,參見附錄B:按需加載資源的大小限制。
一個tag的理想大小是不超過64MB。這能很好地平衡下載速度和本地存儲大小,當設備的存儲空間不足時可以進行清理。
tag的名稱最好能區(qū)分出資源是如何使用的。例如,所有和森林場景有關的資源就可以起名叫forest-scenery
。
創(chuàng)建好tag后就可以分配給資源了。一個資源可以添加多個tag。例如在下圖中,游戲的資源是按關卡和地點來分割的。
如何創(chuàng)建一個新的tag
1、在project navigator中, 選擇工程文件。
2、為需要新tag的target打開project editor 。
3、選擇 Resource Tags 選項卡。
4、點擊選項卡左上角的添加按鈕(+)。
如下圖所示,會顯示一個新的tag輸入框。
5、輸入tag的名稱來替換占位符。
為資源添加tag
可以為任何有效的按需加載資源類型添加tag。具體的有效類型,參見附錄A:
在Asset Catalog中添加tag
1、在project navigator中, 選擇Asset Catalog。
2、在列表中選擇一項 。
3、為選擇的項目打開Attributes inspector。
4、在按需加載資源tag框,輸入tag的名稱。
Xcode會根據輸入的字符進行自動補全提示。
5、按下Return鍵來確認輸入的tag名稱。
注意:輸入一個新的名稱,并按下Return鍵,會創(chuàng)建一個新的tag。
在按需加載資源tag框為工程中的某個文件添加tag
1、在project navigator中, 選擇一個文件。
2、打開實用工具區(qū),點擊File inspector 按鈕。
3、在按需加載資源tag框,輸入tag的名稱。
Xcode會根據輸入的字符進行自動補全提示。
4、按下Return鍵來確認輸入的tag名稱。
注意:輸入一個新的名稱,并按下Return鍵,會創(chuàng)建一個新的tag。
使用Resource Tags選項卡來給工程中的文件添加tag
1、在project navigator中, 選擇工程文件。
2、為target打開project editor 。
3、選擇 Resource Tags 選項卡。
4、在搜索框中,輸入tag的名稱。列表會根據搜索的文字進行過濾。
5、點擊添加按鈕(+),會彈出一個對話框。
6、在輸入框中,輸入資源文件的名稱。
7、選中想要的資源文件,點擊Add。這個資源文件就加上tag了。
注意: Asset Catalogs中的資源必須使用按需加載資源tag框來添加tag。
從tag中刪除資源
可以通過在按需加載資源tag框刪除tag,來將資源從tag中刪除。也可以在Resource Tags 選項卡中刪除資源。
使用Resource Tags選項卡來刪除tag下的資源
在project navigator中, 選擇工程文件。
為target打開project editor 。
選擇 Resource Tags 選項卡。
在搜索框中,輸入tag的名稱。列表會根據搜索的文字進行過濾。
在tag對應的行中,點擊左側的小箭頭來展開tag編輯器(如果沒有展開的話)。
在tag編輯器中,選擇列表中的資源文件。
在tag編輯器中,點擊刪除按鈕(-)。
**在Asset Catalog中添加tag **
在project navigator中, 選擇Asset Catalog。
在列表中選擇一項 。
為選擇的項目打開Attributes inspector。
在按需加載資源tag框,選擇一個tag,按下Delete鍵。
在按需加載資源tag框為工程中的某個文件刪除tag
在project navigator中, 選擇一個文件。
打開實用工具區(qū),點擊File inspector 按鈕。
在按需加載資源tag框,選擇一個tag,按下Delete鍵。
預獲取的tag
通常來說,操作系統(tǒng)是不會下載一個tag下的資源,直到app請求一個tag并且該tag的資源沒有在設備上緩存。一些tag中會包含啟動時需要或者啟動后馬上要用到的資源。
在Resource Tags選項卡的Prefetched界面下,可以把tag分配給三個預獲取優(yōu)先級分類的其中一個。界面展示了按預獲取分類分組的tag。tag可以在分類間拖動。
初始安裝tag(Initial install tags)。只有在初始安裝tag下載到設備后,app才能啟動。這些資源會在下載app時一起下載。這部分資源的大小會包括在App Store中app的安裝包大小。如果這些資源從來沒有被NSBundleResourceRequest
對象獲取過,就有可能被清理掉。
按順序預獲取tag(Prefetch tag order)。在app安裝后會開始下載tag。tag會按照此處指定的順序來下載。
按需下載(Dowloaded only on demand)。當app請求一個tag,且tag沒有緩存時,才會下載該tag。
將tag設置為隨app安裝
在project navigator中, 選擇工程文件。
為target打開project editor 。
選擇 Resource Tags 選項卡。
在tag視圖選擇器,點擊Prefetched。
在內容區(qū),點擊Initial Install Tags分類旁邊的小箭頭。
在內容區(qū),找到你想要隨app安裝的tag。
點擊并拖動該tag到Initial Install Tags列表。
將tag設置為預獲取
在project navigator中, 選擇工程文件。
為target打開project editor 。
選擇 Resource Tags 選項卡。
在tag視圖選擇器,點擊Prefetched。
在內容區(qū),點擊Prefetched Tag Order分類旁邊的小箭頭。
在內容區(qū),找到你想要預獲取的tag。
點擊并拖動該tag到Prefetched Tag Order列表。 tag在列表的位置會決定下載的順序。列表最上面的tag會最先下載。
將tag設置為只在app請求時下載
在project navigator中, 選擇工程文件。
為target打開project editor 。
選擇 Resource Tags 選項卡。
在tag視圖選擇器,點擊Prefetched。
在內容區(qū),點擊Downloaded Only On Demand分類旁邊的小箭頭。
在內容區(qū),找到你想要按需下載的tag。
點擊并拖動該tag到Downloaded Only On Demand列表。
管理按需加載資源
下載和管理按需加載資源是由操作系統(tǒng)完成的。app使用NSBundleResourceRequest來:
請求獲取按需加載資源。
通知操作系統(tǒng)某些資源不再使用。
更新下載的優(yōu)先級。
追蹤下載的進度。
檢查存儲空間不足的通知。
當已下載的某些資源不再使用時,可以用NSBundle中的方法來設置保存優(yōu)先級。
按需加載資源使用下面的4個方法來管理。
app分配并初始化一個NSBundleResourceRequest
對象。需要管理的tag必須在初始化時指定,不能更改。
app請求獲取一個tag下的資源。如果這些資源需要下載,可以更新下載的優(yōu)先級,追蹤下載進度。如果發(fā)生錯誤了,可以采取適當?shù)拇胧?。錯誤包括無效的tag、沒有網絡連接、無權使用蜂窩移動數(shù)據、沒有足夠的空間等等。
app使用這些資源。這些資源的使用方式和該類型的其他資源一樣。
app結束獲取這些資源,并通知系統(tǒng)不再使用這些資源。
在tag下載到設備后的任何時間都可以設置tag的保存優(yōu)先級。
注意:每個NSBundleResourceRequest
對象都只能用于一個請求訪問/結束訪問循環(huán)。
請求訪問
app必須在使用tag的資源之前先請求訪問這些tag。請求訪問的第一步是為tag創(chuàng)建一個NSBundleResourceRequest
對象。一個tag可以由多個NSBundleResourceRequest
對象來管理。
每個NSBundleResourceRequest
實例管理同一個bundle下的加了tag的資源。使用下面的兩個方法來在初始化時設置被管理的tag和bundle:
如果資源都在app的main bundle中,使用 initWithTags:
。
如果資源都在同一個自定義bundle中,使用 initWithTags:bundle:
。
注意:bundle
可以設置為main bundle。
列表4-1展示了一個初始化資源管理器的一個例子,所有加tag的資源都在main bundle中。
列表4-1 初始化一個NSBundleResourceRequest實例
// Initialize an NSBundleResourceRequest with the desired tags
NSSet *tags = [NSSet setWithArray: @[@"birds", @"bridge", @"city"]];
// All the resources are in the main bundle so use the shorter initialization method
resourceRequest = [[NSBundleResourceRequest alloc] initWithTags:tags];
注意:tag和bundle只能在初始化時設置。
請求訪問資源
在初始化NSBundleResourceRequest實例之后,就是請求訪問了。當請求的所有tag下的所有資源都在本地存儲中時,操作系統(tǒng)會持有這些資源,并使用回調通知app這些資源已經可以使用了。更多信息參見第三步按需加載資源的生命周期。
有兩個方法來請求訪問。當資源已在設備上時,這兩個方法都可以允許訪問。不同的是當資源不在設備上時會做什么。
beginAccessingResourcesWithCompletionHandler:
會從 App Store下載這些資源。
conditionallyBeginAccessingResourcesWithCompletionHandler:
不會下載資源。
兩個方法都會在回調block中返回結果。所有的資源都必須已經在設備上才能使用。列表4-2展示了方法beginAccessingResourcesWithCompletionHandler:
。
列表4-2 使用beginAccessingResourcesWithCompletionHandler:
// Request access to the tags for this resource request
[resourceRequest beginAccessingResourcesWithCompletionHandler:
^(NSError * __nullable error)
{
// Check if there is an error
if (error) {
// There is a problem, update app state (should inform user if appropriate)
self.resourcesLoaded = NO;
return;
}
// the resources associated with the the tags are loaded, start using them
self.resourcesAvailable = YES;
}
];
注意:在允許訪問之后,不要使用同一個NSBundleResourceRequest
實例再次請求訪問。
檢查tag是否已在設備上
有時當tag不在設備上時,你并不想開始下載它們。例如,當設備使用低帶寬網絡,并且高質量的圖片和聲音不在設備上時,你可以使用低質量資源。
當tag已在設備上,conditionallyBeginAccessingResourcesWithCompletionHandler:
會允許訪問。如果tag不在設備上,app需要調用beginAccessingResourcesWithCompletionHandler:
來下載它們。列表4-3展示了一個檢查tag是否在設備上的例子。
注意:如果conditionallyBeginAccessingResourcesWithCompletionHandler:
返回YES
,就不要調用beginAccessingResourcesWithCompletionHandler:
了。
列表4-3 使用conditionallyBeginAccessingResourcesWithCompletionHandler:
// Request access to tags that may already be on the device
[resourceRequest conditionallyBeginAccessingResourcesWithCompletionHandler:
^(BOOL resourcesAvailable)
{
// Check if the resources are available
if (resourcesAvailable) {
// the resources associated with the the tags are loaded, start using them
self.highQualityResourcesAvailable = YES;
} else {
// The resources are not on the device and need to be loaded
// Queue up a call to custom method for loading the tags using
// beginAccessingResourcesWithCompletionHandler:
dispatch_async(dispatch_get_main_queue(), ^{
[self loadLowerQualityTags];
}
}
}
];
何時請求tag
因為從App Store下載tag會花一些時間,你可以在需要使用tag之前請求tag。下載時間取決于總共要下載的大小,網絡連接的速度,以及操作系統(tǒng)能分配多少資源來處理下載。
在沒有帶寬限制的理想情況,在300Mbps的 802.11n或者LTE網絡(299.6Mbps)上,下載一個64MB的tag至少要用1.7秒。但實際情況是連接到因特網的速度要遠低于300Mbps。
下載優(yōu)先級
資源請求有一個默認的優(yōu)先級,這可以隨時更改,包括下載時。低優(yōu)先級使用更少的操作系統(tǒng)資源,為其他任務騰出資源。這也會降低下載速度。低優(yōu)先級有利于最大化app執(zhí)行效率。列表4-4展示了一個更改請求優(yōu)先級的例子。
列表4-4 更改下載優(yōu)先級
// The priority is a between 0.0 and 1.0
self.resourceRequest.loadingPriority = 0.1;
提高下載優(yōu)先級會使用更多的操作系統(tǒng)資源,相應地提高下載速度,降低app效率。如果下載很緊急,app可以將下載優(yōu)先級設置為NSBundleResourceRequestLoadingPriorityUrgent
。這會告訴操作系統(tǒng)盡可能多地分配資源來處理下載。一個使用場景就是用戶在下載完成之前什么也做不了。列表4-5展示了一個當用戶需要等待時,設置緊急優(yōu)先級的例子
列表4-5 提高請求的優(yōu)先級
// Raise the priority based on the urgency
if (self.userWaiting) {
// The user is waiting, request the maximum download time
self.resourceRequest.loadingPriority = NSBundleResourceRequestLoadingPriorityUrgent;
} else {
// Set a higher priority
self.resourceRequest.loadingPriority = 0.8;
}
上面的代碼直接使用了一個固定浮點數(shù)設置優(yōu)先級。你也可以根據app的效率來更新下載優(yōu)先級。
追蹤下載進度
在下載開始之后,請求會開始更新progress
,這是一個NSProgress
類型的屬性。app通過對progress.fractionCompleted
進行KVO來追蹤下載進度。這需要開始和結束觀察,以及添加當值改變時執(zhí)行的代碼。列表4-6展示了如何開始和結束觀察進度。列表4-7展示了當值改變時執(zhí)行的代碼。
列表4-6 開始和結束追蹤下載進度
// Start observing fractionCompleted for the progress
[self.resourceRequest.progress addObserver:self forKeyPath:@"fractionCompleted" options:NSKeyValueObservingOptionNew context:NULL];
// Stop observing fractionCompleted for the progress
[self.resourceRequest.progress removeObserver:self forKeyPath:@"fractionCompleted"];
列表4-7 當fractionCompleted
的值改變時執(zhí)行的代碼
//
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// Check for the progress object and key
if ((object == self.resourceRequest.progress) && ([keyPath isEqualToString:@"fractionCompleted])) {
double progressSoFar = self.resourceRequest.progress.fractionCompleted;
// do something with the value
}
}
追蹤下載的兩個重要用途是:
調整下載優(yōu)先級。如果下載時間過長可以提高優(yōu)先級,如果時間充??梢越档蛢?yōu)先級。
為用戶提供下載進度反饋??梢允褂靡粋€簡單的進度條來反饋fractionCompleted
的值。
暫停和取消下載
正在進行的下載可以被暫停、恢復、取消。這通過progress
屬性,以及NSProgress
提供的方法來完成。更多信息參見NSProgress類參考。
列表4-8 暫停、恢復、取消當前的下載
// Pause the current download
[self.resourceRequest.progress pause];
// Resume the current download
[self.resourceRequest.progress resume];
// Cancel the current download
[self.resourceRequest.progress cancel];
結束訪問
當app不再使用資源時,結束訪問能讓操作系統(tǒng)可以回收存儲空間。這也就是按需加載資源基礎中按需加載資源的生命周期的第4步。有2種方法結束訪問:
給請求發(fā)送endAccessingResources
,如列表4-9所示。
釋放這個請求。
列表4-9 結束對tag的訪問
// End access by calling this method or deallocating the NSBUndleResourceRequest instance
[self.resourceRequest endAccessingResources];
在endAccessingResources
調用之后,這個請求就不能再用于請求訪問了。如果app還需要訪問同一個tag,需要再重新創(chuàng)建一個NSBundleResourceRequest
實例。
設置保留優(yōu)先級
某些tag中的資源可能比其他的更重要。例如,應用內購買或者基本功能的資源就會被更頻繁地用到。app可以為這些tag設置一個高保留優(yōu)先級。當操作系統(tǒng)開始清理tag時,會從最低保留優(yōu)先級開始。
可以使用NSBundle
的方法來設置和檢查保留優(yōu)先級。
列表4-10 為tag檢查和設置保留優(yōu)先級
// Check the preservation priority for the llama in-app purchase module
double currentPriority = [[NSBundle mainBundle] preservationPriorityForTag:@"iap-llamas"];
// Set the priority to the maximum of 1.0 (the default is 0.0)
// The call to set the priority takes a set of tags
NSSet *tags = [NSSet setWithArray: @[@"iap-llamas"]];
[[NSBundle mainBundle] setPreservationPriority:1.0 forTags:tags];
低存儲空間警告
當操作系統(tǒng)沒有辦法為當前正在請求的資源釋放出足夠的空間時,系統(tǒng)會發(fā)出一個通知。你的app應該停止訪問所有不再使用的tag,如上面結束訪問描述的。如果操作系統(tǒng)不能釋放出足夠空間,app會被終止。
例如,在一個有多個關卡的游戲中,用戶正在第4關,app請求第3、5、6關的tag。當?shù)痛鎯臻g警告發(fā)生時,app可以釋放第3、6關的tag。列表4-11展示了注冊低存儲空間通知的代碼。列表4-12展示了釋放不需要tag的方法。
列表4-11 注冊NSBundleResourceRequestLowDiskSpaceNotification
通知
// End access by calling this method or deallocating the NSBUndleResourceRequest instance
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(lowDiskSpace:) name:NSBundleResourceRequestLowDiskSpaceNotification object:nil];
注冊通知一般由app delegate或者主view來完成。
列表4-12 低存儲空間通知的處理
// Notification handler for low disk space warning
-(void)lowDiskSpace:(NSNotification*)theNotification
{
// Free the lower priority resource requests
for (NSBundleResourceRequest *atRequest in self.lowPriorityRequests) {
// End accessing the resources
[atRequest endAccessingResources];
}
// clear lowPriorityRequests preventing multiple calls to endAccesingResource
[self.lowPriorityRequests removeAllObjects];
}
lowPriorityRequests
不是由操作系統(tǒng)提供的。它是一個需要由app創(chuàng)建和維持的mutable set 。
調試
在你開發(fā)的過程中可能會遇到幾類問題。不同類別的問題需要使用不同的工具來調試。主要有以下幾類問題:
網絡連接:慢速或無網絡連接產生的問題。
本地存儲空間。本地存儲空間不足無法下載。
意外狀態(tài)。tag處于意外狀態(tài)。例如,一個tag顯示正在使用中,但app的所有模塊都已經結束訪問了。
意外狀態(tài)
調試意外狀態(tài)最有用的工具就是Xcode中的磁盤儀表了。磁盤儀表中會顯示tag的當前狀態(tài),如下圖所示。
磁盤儀表會顯示每個tag的大小和狀態(tài)。大小是針對當前設備裁切后的。
tag的狀態(tài)
表5-1描述了磁盤儀表中tag可能處于的狀態(tài)。
表5-1 tag的狀態(tài)
| 狀態(tài) | 描述 |
|---|---|
| 未下載 | 在此調試會話中,tag還沒有被下載到設備上。 |
| 部分已下載 | 可能由于連接中斷造成tag的一部分已下載。 |
| 下載中 | tag正在下載中。可能會顯示一個進度條。 |
| 已下載 | tag已在設備上,且沒有被任何NSBundleResourceRequest 對象使用。 |
| 使用中 | tag已在設備上,且正在被app使用。 |
| 被清理 | tag之前在設備上,現(xiàn)在已經被清理出本地存儲。在被使用前,必須先下載。 |
**使用磁盤儀表 **
在模擬器或真機上運行app都可以使用磁盤儀表。
打開磁盤儀表。
選擇View > Navigators > Show Debug Navigator。
使用Scheme彈框選擇一個target和設備。
選擇Product > Run來啟動app。app會在選擇的設備上啟動,并連接調試器。
在Debug Navigator中的列表中點擊磁盤儀表。磁盤儀表會在workspace窗口的內容區(qū)顯示。
向下滾到直到顯示資源分類。你可以調整內容區(qū)的大小來顯示全部tag。
附錄A:資源類型
下表列出了可以加tag的資源類型。
表A-1 按需加載資源類型
| 類型 | Asset catalog | 文件 |
|---|---|---|
| 圖像文件 | - | √ |
| 多媒體文件 | - | √ |
| Asset catalog image set | √ | - |
| Asset catalog folder | √ | - |
| SpriteKit scene | - | √ |
| SpriteKit texture atlas | √ | √ |
| SpriteKit particle | - | √ |
| WatchKit Complication | √ | - |
| OpenGL shader | - | √ |
| 數(shù)據文件 | √ | √ |
數(shù)據文件可以包括除了可執(zhí)行的Swift、Objective-C、C、或者C++二進制包以外的任何類型數(shù)據。由腳本語言生成的文件可以用作按需加載資源。
附錄B:資源大小限制
存儲空間大小
在App Store 提交時和app運行時,按需加載資源使用的存儲空間大小是有限制的。
表B-1 資源大小
| 項目 | 大小 | Slicing |
|---|---|---|
| app二進制包 | 2GB | √ |
| Initial install tags | 2GB | √ |
| Initial install and prefetched tags | 4GB | √ |
| In use on-demand resources | 2GB | √ |
| Hosted on-demand resources | 20GB | - |
Slicing。表示這個大小是在App裁切之前還是之后。
app二進制包。表示裁切后的下載到設備上的安裝包大小。
Initial install tags。裁切后標為初始安裝tag的全部大小。
Initial install and prefetched tags。裁切后標為初始安裝和預獲取tag的全部大小。
In use on-demand resources。裁切后app在任何時刻使用中的tag的大小。只要有一個NSBundleResourceRequest
對象訪問tag,tag就算是在使用中。
Hosted on-demand resources。由App Store托管的tag未裁切的大小。