美文网首页
iOS组件化-资源管理

iOS组件化-资源管理

作者: ty_Chen | 来源:发表于2019-12-20 11:22 被阅读0次

    在组件化前期的工作中,我们会面临如何管理图片、音视频等资源的问题。我们需要关注的问题是如何将相应的资源和组件一起打包,并保证能够在组件内和组件间的正常使用。以下内容均针对于使用CocoaPods方式组件化对资源文件管理的讨论。

    文件管理方式:

    1. 集中式管理

    将所有的资源文件做成一个组件,其它相应的组件依赖该资源组件,通过组件暴露的相关接口获取对应的资源。

    2. 分散式管理

    将资源文件进行清晰分类,对应的资源文件嵌入至对应的组件中,如有共用文件,抽取公共资源组件将公共资源放入该组件中,或者将公共资源直接放至主工程中。

    集中式管理与分散式管理优缺点对比:
    总结建议:

    集中式管理可方便维护,可对项目文件进行统一管理,此外还可降低文件冗余的概率,可用于较大、耦合严重的项目。倘若是新项目或者组件对主工程依赖性不强的组件,可采用分散式管理,将组件的相关资源与组件绑定。

    resources和resource_bundles

    resouresresource_bundlesCocoaPods两种资源文件引用的方式。

    1. resource/resources

    resourceresources两个属性功能相同,不同的是resources可以批量指定文件资源,resource只能指定单个文件资源。

    1.1 语法
    spec.resource = 'Resources/HockeySDK.bundle'
    spec.resources = ['Images/*.png', 'Sounds/*']
    
    1.2 官方描述 Podspec语法官方介绍

    resources将指定的资源复制到目标bundle,我们强烈建议开发者使用 resource bundles去构建静态资源库。使用resources属性仅仅是将指定的文件资源复制到目标bundle,如此Xcode不会对相关资源进行优化操作。

    看完官方描述,我们第一直觉就会放弃使用这种方式了。虽然如此,但是我们还是去看看如果使用这种方式具体会产生哪些影响。

    1.3 resource探究

    使用pod lib create SCResource_Resources命令创建项目。打开Example中的项目,并删除SCResource_Resources.podspec中无用的代码。如下图所示。

    1.3.1 resource不嵌入xcassets文件

    选中ReplaceMe.m文件,右键Show in Finder,调至上一级文件夹,看到ClassesAssets文件夹。我们把ReplaceMe.m删除,并删除SCResource_Resources.podspec中的s.source_files,因为我们在资源组件中暂时不用编辑代码。然后把事先准备好的图片资源放入Assets文件夹下,并设置resource属性。最终如下图所示。

    终端pod install后,便可以看到图片资源已经被加到Resources文件夹下。

    查看资源文件在包中的位置

    真机运行,选择Products文件夹下的SCResource_Resources_Example.app右键Show in Finder,选中SCResource_Resources_Example右键,选择显示包内容,就可以看到我们添加的Images文件夹。查看并记录文件夹的大小。发现和事先我们准备的文件夹大小相同,均为21.5M。

    资源文件获取

    一般情况下,我们在项目中获取图片都是通过使用imageNamed:方法去获取。那么现在我们把图片资源放在组件中,通过这样的方式也能够获取吗?
    我们在Example项目中的SCViewController.mviewDidLoad方法中键入如下代码:


    前面我们查看过Images最终在APP中的路径,并且容易找到goodluck_smile图片的路径是Images/好运墙/goodluck_smile。运行项目,发现我们拿到的image对象是nil

    很糟糕,我们没有获取到对应的图片。查看注释可以知道imageNamed:是从main bundle中获取文件资源,那么如果我们把图片放在主工程中的Images.xcassets文件中,这里的文件在最终的包中的路径是什么呢?带着这样的疑问,我们简单地把一张图片(goodluck_smile)放入Images.xcassets中,真机运行后,通过上述查看资源文件在包中的位置的操作方法进行查看。

    可以看到多出了Assets.car文件,由此可以知道,Images.xcassets中的图片资源,最终会被打包成Assets.car文件,也从侧面可以说明Assets.car文件所在的目录就是main bundle的路径,那么为什么组件中的图片没有被正常获取呢?难道是因为我们路径问题?
    前面我们已经说过goodluck_smile图片是在Images/好运墙/ 下,那么我么手动拼接试试。为了排除其它影响,我们删除掉前面在Images.xcassets中的图片文件,并运行。

    这时候,我们正确获取到了我们想要的图片。现在我们可以通过代码来获取到组件中的图片了,需要注意的点是需要传入图片的相对路径,那么在xib中又如何呢?
    我们再Main.storyboard中添加一个UIImageView,并直接设置goodluck_smile图片,瞬间就心情大好,因为立马就看到Main.storyboard显示了对应的图片。

    真机运行,看看会不会有什么问题。
    运行后发现,我们设置的图片没有正常显示,那么也是因为我们要填写相对路径的原因吗?我们去试试。

    这时候,发现Main.storyboard没有正常显示图片,但是真机运行后,图片显示正常。

    总结:

    使用resource/resources直接存放文件资源时,无论是通过代码获取图片,还是在xib中设置图片,都需要填写完整的相对路径。当然如果你想直接通过设置图片名称的方式获取图片,那么你必须将图片直接暴露在resources文件下,不能新建文件对相关资源做整理。

    1.3.2 resource嵌入xcassets文件

    在没有组件化时,我们一般把图片资源都放在Images.xcassets文件内管理,其为我们提供了许多优化点和一些方便的功能,所以我们可能也希望在组件中也利用这些优化和功能。那么在resource中如何通过xcassets来管理图片呢?其实很简单,只需在组件的Assets文件夹下创建Asset Catalog文件,再将图片资源拖入即可。

    这里需要注意的是:在创建Asset Catalog文件后,其目录可能不在组件的Assets文件下,需要手动将其拖入至文件下。

    pod install后,对项目进行编译,如果出现如下错误,则选择File -> Workspace Settings -> Build SystemNew Build System(Default)改为Legacy Build System即可。

    使用上文提到的查看资源文件在包中的位置的方式查看文件资源,前面我们也提及到,xcassets文件最后打包进APP是会转成Assets.car文件的,我们找到该文件,并查看该文件的大小。

    文件大小变成了69.1M,是原先21.5M的好几倍,这会大大增大包的大小。

    资源文件获取

    在查看资源文件路径后,我们发现,其路径和在主工程中的Images.xcassets在包中的路径相同,那么可以推测,正常使用相关方法应该可以获取到资源文件。

    同样在ViewDidLoad方法中键入一下代码,看能否正确获取图片资源。断点运行后,发现可正常获取。

    使用xib方式也一样,这里就不再截图,大家可以自己尝试。

    总结:

    resource嵌入xcassets文件时,资源文件会被copymain bundle中,可以正常获取资源文件,但是会造成APP大小变大,因此不建议使用。

    2. resource_bundle/resource_bundles

    resource/resources类似,resource_bundle/resource_bundles功能相同,区别在与指定一个和多个。

    2.1 语法
    spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' }
    spec.resource_bundles = {
        'MapBox' => ['MapView/Map/Resources/*.png'],
        'MapBoxOtherResources' => ['MapView/Map/OtherResources/*.png']
    }
    
    2.2 官方描述 Podspec语法官方介绍

    重点翻译:强烈建议使用该方式为Pod构建静态库,文件资源通过键值匹配资源,bundle的名称应该包含Pod的名称来降低名称冲突的可能性。

    2.3 resource_bundle探究

    下面同样通过是否嵌入xcassets文件来分析这两种情况的优劣。

    2.3.1 resource_bundle不嵌入xcassets文件

    不嵌入xcassets文件时,和resource一样,直接将文件资源拖入至Assets文件夹下,具体参考上文resource不嵌入xcasset文件中的内容。然后修改podspec文件制定文件资源的方式,如下图所示。

    pod install,真机运行,查看资源文件在包中的位置,可以看到一个SCResource_Resources.bundle的文件。查看该文件的大小为21.1M,比原文件略小。

    再选择SCResource_Resources.bundle右键显示包内容,可看到我们放进去的Images图片文件夹。

    资源文件获取

    前面在resource的章节中,我们已经知道需要通过拼接资源的相对路径才能获取相应的资源,所以我们这里也尝试看看会发生什么。

    ViewDidLoad方法中键入下面代码:

    UIImage *image = [UIImage imageNamed:@"SCResource_Resources.bundle/Images/好运墙/goodluck_smile"];
    

    断点查看是否能正常获取图片资源。

    xib中同样这样拼接,真机运行,看能否正常显示图片。

    运行后,我们可以如预期一样获取资源文件。

    总结:

    resource_bundle不嵌入xcasset文件,需拼接文件的相对路径才能正确获取图片资源。

    2.3.2 resource_bundle嵌入xcassets文件

    嵌入xcassets文件时,也和resource一样,创建xcassets文件,拖入文件资源,并拖入至Assets文件夹下,具体参考上文resource嵌入xcasset文件中的内容。

    pod install并真机运行,查看资源文件在包中的位置,我们同样可以看到SCResource_Resources.bundle文件,查看文件大小,可以看到只有16.8M,比前面所有情况都要小。

    再选择SCResource_Resources.bundle右键显示包内容,可看到我们放进去的Assets.car文件。与前文的情况一致。

    资源文件获取

    resource的章节中,如果嵌套xcassets文件,我们可以直接通过图片名称来获取文件资源,那么这里是不是类似呢,我们来试试。

    viewDidLoad方法中键入下面代码:

    UIImage *image = [UIImage imageNamed:@"goodluck_smile"];
    

    运行,查看image对象是否存在。

    很遗憾,结果为nil。那么我们拼接路径呢?同样在viewDidLoad方法中键入下面代码:

    UIImage *image = [UIImage imageNamed:@"SCResource_Resources.bundle/goodluck_smile"];
    

    运行,查看image对象是否存在。

    同样的结果,还是nil

    使用这种方式,我们需要换一个方法去获取指定资源,我们需要调用UIImageimageNamed:inBundle: compatibleWithTraitCollection:方法。指定bundle和图片的名称即可。

    NSString *bundleName = @"SCResource_Resources";
    NSString *imageBundlePath = [[NSBundle mainBundle] pathForResource:bundleName ofType:@"bundle"];
    NSBundle *imageBundle = [NSBundle bundleWithPath:imageBundlePath];
    
    UIImage *image = [UIImage imageNamed:@"goodluck_smile" inBundle:imageBundle compatibleWithTraitCollection:nil];
    

    运行,查看image对象是否存在

    运行结果如预期,可获取对应文件资源。

    xib中如何设置呢?可以添加分类暴露bundleNameimageName使用IBInspectable修饰,调用imageNamed:inBundle: compatibleWithTraitCollection:方法。

    总结:

    resource_bundle嵌入xcasset文件,包文件大小相对于其它情况较小,但获取文件资源时,需要封装方法调用UIImageimageNamed:inBundle: compatibleWithTraitCollection:方法。

    总结

    使用CocoaPods方式组件化,对文件资源进行管理,建议使用resource_bundle/resource_bundles嵌入xcassets文件的方式。这样一来可以使用xcassets的一些特性和优化,也能够在一定程度上减小包的体积。

    相关文章

      网友评论

          本文标题:iOS组件化-资源管理

          本文链接:https://www.haomeiwen.com/subject/inbbnctx.html