0

这是基本问题:我需要一个视图加载机制,尝试从 Documents 中下载的 NIB 创建一个视图,如果无法创建视图,则返回到主包。

在让它发挥作用之前,我经历了很多研究和反复试验,所以我想与其他人分享解决方案。

4

1 回答 1

0

以下是步骤:

1) 以正常方式在主包中创建 NIB。我建议使用指向文件夹的文件组,以将所有资源放在一起,以用于下载的捆绑包。我们称之为NIB_Resources。

在 Project Navigator 中的文件夹下创建 NIB:

  1. 右键单击文件组。
  2. 选择新文件...</li>
  3. 选择用户界面,然后选择查看。

2) 为资产包添加一个目标。

  1. 单击目标面板中的 +。
  2. 在 OS X 下的 Framework and Library 类别中选择 Bundle 模板。它属于该类别,因为它是一种资产库。
  3. 对于产品名称,输入您要调用资产库的名称。保留其他所有内容,然后选择要将产品添加到的项目。
  4. 在新产品的 Build Settings 中,将 Base SDK 从最新的 OS X 更改为最新的 iOS。

3) 将资产添加到资产包。

  1. 为新产品选择 Copy Bundle Resources Build Phase。
  2. 拖放要包含在捆绑包中的资产。如果可以添加资产,光标将显示 + 图标。

4) 构建资产包。

  1. 为新创建的目标选择方案。
  2. 选择 iOS 设备作为构建目标。
  3. 建造。
  4. 如果这样做正确,那么新捆绑包的产品应该在 Project Navigator 的 Products 文件夹下从红色变为黑色。

5) 压缩资产包

  1. 右键单击 Products 文件夹中新建的产品,然后选择 Show in Finder。
  2. 将包复制到一个位置,例如该项目专用目录中的某个文件夹。
  3. 右键单击包含捆绑包和可能的其他 NIB 文件、图像等的目录。
  4. 选择压缩。

6) 将资产包上传到您有权下载的位置。

7) 下载压缩包:

下面的代码隐藏在便利函数中,在一个处理许多低级文件系统操作的便利文件中。FS 前缀是指文件系统。

FSDownloadTempFileWithURLString在返回主线程之前,可以从辅助线程调用。

我使用NSData同步方法,initWithContentsOfURL:因为调用很可能是从辅助线程进行的。基本策略是将 zip 文件下载到一个临时位置(Caches 目录通常是一个很好的选择),然后再进行任何必要的准备并将文件解压缩到 Documents 目录。Apple 采用了在头文件中定义内联静态操作的方法。

//文档目录
#define FSDocumentsDirectory [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]

//缓存目录
#define FSCachesDirectory [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject]

/**
 * 获取缓存目录下文件的路径。给定的文件名可以有
 * 多个文件分隔符。
 */
内联静态 NSString* FSCachesPath(NSString *filename)
{
    return [FSCachesDirectory stringByAppendingPathComponent:filename];
}


/**
 * 从指定的 URL 下载文件,并复制到缓存目录,与 URL 的文件名相同的文件名。
 *
 * 返回结果。
 */
内联静态 BOOL FSDownloadTempFileWithURLString(NSString *urlString)
{
    NSData *data = getDataFromURL(urlString);
    如果(!数据){
        //错误已经记录
        返回错误;
    }

    NSString *path = FSCachesDirectory;
    NSString *filename = [urlString lastPathComponent];
    path = [path stringByAppendingPathComponent:filename];

    NSError *error = nil;
    if (![data writeToFile:path options:NSDataWritingAtomic error:&error]) {
        NSLog(@"尝试将文件写入时发生错误:%@\n", path);
        NSLog(@"%@", 错误);

        返回错误;
    }

    返回真;
}

/**
 * 从指定的 URL 获取数据。
 */
内联静态 NSData* getDataFromURL(NSString *urlString)
{
    NSString *escapedUrlString = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

    NSURL *url = [NSURL URLWithString:escapedUrlString];
    NSData *data = [[NSData alloc] initWithContentsOfURL:url];
    如果(!数据){
        debugLog(@"无法下载文件:%@", escapedUrlString);
        返回零;
    }

    返回数据;
}

8) 使用SSZipArchive或类似的方法将下载文件解压缩到 Documents 目录:

NSString *cachesPath = FSCachesPath(URL_RESOURCE_FILENAME);
if (![SSZipArchive unzipFileAtPath:cachesPath toDestination:FSDocumentsDirectory delegate:nil]) {
    返回;
}

9) 最后,尝试从 Documents 目录中包中的 NIB 文件加载视图,然后返回到主包。

下面的FSResourceNib操作可以从试图从 Nib 加载视图的视图控制器中调用,如下所示:

UIView *view = FSResourceNib(ResourcesBundle, nibName, self);
/**
 * 从文档目录中获取 NIB,否则回退到捆绑包。
 *
 * 如果发生错误,则返回 nil。
 */
内联静态 UIView* FSResourceNib(NSString *bundleFilename, NSString *nibName, id owner)
{
    UIView *resourceView = nil;

    //如果文档路径中不存在bundld,则使用主包
    NSString *resourcePath = FSDocumentsPath(bundleFilename);
    if ([[NSFileManager defaultManager] fileExistsAtPath:resourcePath]) {
        NSBundle *resourceBundle = [NSBundle bundleWithPath:resourcePath];

        @尝试 {
            //尝试从给定的包中加载NIB
            resourceView = [[resourceBundle loadNibNamed:nibName owner:owner options:nil] lastObject];
        }
        @catch (NSException *异常) {
            //什么都不做 - 将尝试主包
        }
    }

    //如果从给定包加载失败,尝试从主包加载
    如果(!resourceView){
        NSBundle *resourceBundle = [NSBundle mainBundle];

        @尝试 {
            resourceView = [[resourceBundle loadNibNamed:nibName owner:owner options:nil] lastObject];
        }
        @catch (NSException *异常) {
            // 什么都不做 - 将返回 nil,表示发生了错误
        }
    }

    返回资源视图;
}
于 2015-08-22T05:00:57.577 回答