这是基本问题:我需要一个视图加载机制,尝试从Documents中下载的NIB创建视图,然后在无法创建视图的情况下回退到主包。
在进行此项工作之前,我经历了大量的研究和反复试验,所以我想与其他人分享解决方案。
答案 0 :(得分:0)
以下是步骤:
1)以正常方式在主包中创建NIB。我建议使用指向文件夹的文件组,以保留将用于下载的包的所有资产。我们称之为NIB_Resources。
在Project Navigator中的文件夹下创建NIB:
2)为资产包添加目标。
3)将资产添加到资产包中。
4)构建资产包。
5)压缩资产包
6)将资产包上传到您具有下载访问权限的位置。
7)下载压缩资产包:
以下代码隐藏在便捷功能中,处理许多低级文件系统操作的便捷文件。 FS前缀是指文件系统。
在返回主线程之前,可以从辅助线程调用 FSDownloadTempFileWithURLString
。
我使用NSData
同步方法initWithContentsOfURL:
,因为调用很可能是从辅助线程进行的。基本策略是在执行任何必要的准备工作并将文件解压缩到Documents目录之前,将zip文件下载到临时位置(Caches目录通常是用于此目的的良好候选者)。在Apple文件中采用了在头文件中定义内联静态操作的方法。
//Documents directory #define FSDocumentsDirectory [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] //Caches directory #define FSCachesDirectory [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject] /** * Get the path to a file under the caches directory. The given filename can have * multiple file separators. */ inline static NSString* FSCachesPath(NSString *filename) { return [FSCachesDirectory stringByAppendingPathComponent:filename]; } /** * Download a file from a specified URL, and copy to the caches directory, to the same filename as the URL's filename. * * Returns the result. */ inline static BOOL FSDownloadTempFileWithURLString(NSString *urlString) { NSData *data = getDataFromURL(urlString); if (!data) { //Error already logged return FALSE; } NSString *path = FSCachesDirectory; NSString *filename = [urlString lastPathComponent]; path = [path stringByAppendingPathComponent:filename]; NSError *error = nil; if (![data writeToFile:path options:NSDataWritingAtomic error:&error]) { NSLog(@"Error occurred while trying to write the file to: %@\n", path); NSLog(@"%@", error); return FALSE; } return TRUE; } /** * Get the data from a specified URL. */ inline static NSData* getDataFromURL(NSString *urlString) { NSString *escapedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSURL *url = [NSURL URLWithString:escapedUrlString]; NSData *data = [[NSData alloc] initWithContentsOfURL:url]; if (!data) { debugLog(@"Could not download file: %@", escapedUrlString); return nil; } return data; }
8)使用SSZipArchive
或类似内容将下载解压缩到Documents目录:
NSString *cachesPath = FSCachesPath(URL_RESOURCE_FILENAME); if (![SSZipArchive unzipFileAtPath:cachesPath toDestination:FSDocumentsDirectory delegate:nil]) { return; }
9)最后,尝试从Documents目录的bundle中的NIB文件加载一个视图,然后回退到主bundle。
可以从尝试从Nib加载视图的视图控制器调用下面的FSResourceNib
操作,如下所示:
UIView *view = FSResourceNib(ResourcesBundle, nibName, self);
/** * Get a NIB from the documents directory, otherwise fall back to the bundle. * * Returns nil, if an error occurs. */ inline static UIView* FSResourceNib(NSString *bundleFilename, NSString *nibName, id owner) { UIView *resourceView = nil; //If bundld doesn't exist in the documents path, then use the main bundle NSString *resourcePath = FSDocumentsPath(bundleFilename); if ([[NSFileManager defaultManager] fileExistsAtPath:resourcePath]) { NSBundle *resourceBundle = [NSBundle bundleWithPath:resourcePath]; @try { //Try to load the NIB from the given bundle resourceView = [[resourceBundle loadNibNamed:nibName owner:owner options:nil] lastObject]; } @catch (NSException *exception) { //do nothing - will try main bundle } } //If loading from the given bundle failed, try loading from the main bundle if (!resourceView) { NSBundle *resourceBundle = [NSBundle mainBundle]; @try { resourceView = [[resourceBundle loadNibNamed:nibName owner:owner options:nil] lastObject]; } @catch (NSException *exception) { //do nothing - will return nil, indicating an error occurred } } return resourceView; }