iOS开发基础57-换肤功能与静态库开发指南

一、iOS 换肤功能

1. 换肤功能的思路

实现换肤功能的几点思路:

  1. 解决方案1:基于颜色的图片命名规范

    • 问题1:每套图片的文件名必须遵循“颜色+名称.png”格式。
    • 问题2:如果将某一图片应用到其他皮肤时会比较麻烦。
  2. 解决方案2:利用 Bundle

    • 不同皮肤的图片文件保存在不同的 Bundle 中。
    • 问题:平面设计师维护不方便。
  3. 解决方案3:利用文件夹(蓝色)

    • 不同皮肤的图片文件保存在不同的文件夹中。
    • 好处:便于平面设计师维护。

此外,将用户上次使用的皮肤保存在用户偏好中,以便下次启动应用时能显示之前选中的皮肤。

2. 可能遇到的问题

问题一:默认没有皮肤颜色

解决方法:手动设置默认皮肤颜色。

if (_skinColor == nil) {
    _skinColor = @"blue";
}
问题二:用户选中皮肤后,下次打开显示之前选中的皮肤

解决方法:将用户上次使用的皮肤保存在用户偏好中。

+ (void)setSkinColor:(NSString *)skinColor {
    _skinColor = skinColor;
    
    // 记录用户选中的皮肤
    [[NSUserDefaults standardUserDefaults] setObject:skinColor forKey:skinColorKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

// 取出用户之前选中的皮肤
_skinColor = [[NSUserDefaults standardUserDefaults] objectForKey:skinColorKey];
问题三:图片命名不规范

解决方法:拷贝图片时用真实的文件夹,每种颜色的文件夹名用颜色名来命名。

+ (UIImage *)skinToolWithImageName:(NSString *)imageName {
    NSString *imageNamePath = [NSString stringWithFormat:@"skin/%@/%@", _skinColor, imageName];
    return [UIImage imageNamed:imageNamePath];
}
问题四:多控制器的换肤功能

解决方法:在 viewWillAppear: 方法中写换肤相关的代码,使换肤在多个控制器中生效。

3. 工具类封装

SkinTool.h

#import <UIKit/UIKit.h>

@interface SkinTool : NSObject

+ (void)setSkinColor:(NSString *)skinColor;
+ (UIImage *)skinToolWithImageName:(NSString *)imageName;
+ (UIColor *)skinToolWithLabelBgColor;

@end

SkinTool.m

#import "SkinTool.h"

NSString *const skinColorKey = @"skinColor";

@implementation SkinTool

static NSString *_skinColor;

+ (void)initialize {
    _skinColor = [[NSUserDefaults standardUserDefaults] objectForKey:skinColorKey];
    if (_skinColor == nil) {
        _skinColor = @"blue";
    }
}

+ (void)setSkinColor:(NSString *)skinColor {
    _skinColor = skinColor;
    [[NSUserDefaults standardUserDefaults] setObject:skinColor forKey:skinColorKey];
    [[NSUserDefaults standardUserDefaults] synchronize];
}

+ (UIImage *)skinToolWithImageName:(NSString *)imageName {
    NSString *imageNamePath = [NSString stringWithFormat:@"skin/%@/%@", _skinColor, imageName];
    return [UIImage imageNamed:imageNamePath];
}

+ (UIColor *)skinToolWithLabelBgColor {
    NSString *bgColorFileName = [NSString stringWithFormat:@"skin/%@/BgColor.plist", _skinColor];
    NSString *bgColorFilePath = [[NSBundle mainBundle] pathForResource:bgColorFileName ofType:nil];
    NSDictionary *bgColorDict = [NSDictionary dictionaryWithContentsOfFile:bgColorFilePath];
    NSString *bgColorString = bgColorDict[@"LabelBgColor"];
    NSArray *bgColorArray = [bgColorString componentsSeparatedByString:@","];
    NSInteger red = [bgColorArray[0] integerValue];
    NSInteger green = [bgColorArray[1] integerValue];
    NSInteger blue = [bgColorArray[2] integerValue];
    return [UIColor colorWithRed:red / 255.0 green:green / 255.0 blue:blue / 255.0 alpha:1.0];
}

@end

4. 使用示例

设置橘色皮肤:

- (IBAction)switchOrangeSkin {
    [SkinTool setSkinColor:@"orange"];
    [self switchSkinImages];
}

- (void)switchSkinImages {
    self.faceImageView.image = [SkinTool skinToolWithImageName:@"face"];
    self.heartImageView.image = [SkinTool skinToolWithImageName:@"heart"];
    self.rectImageView.image = [SkinTool skinToolWithImageName:@"rect"];
    self.testLabel.backgroundColor = [SkinTool skinToolWithLabelBgColor];
}

在其他控制器中:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.faceImageView.image = [SkinTool skinToolWithImageName:@"face"];
    self.heartImageView.image = [SkinTool skinToolWithImageName:@"heart"];
    self.label.backgroundColor = [SkinTool skinToolWithLabelBgColor];
}

二、静态库

1. 简介

库是程序代码的集合,是共享程序代码的一种方式。根据源代码的公开情况,库可以分为两种:

  • 开源库:公开源代码,如 SDWebImage、AFNetworking。
  • 闭源库:不公开源代码,看不到具体实现。分为静态库和动态库。

2. 静态库和动态库

静态库和动态库的形式分别是:

  • 静态库.a.framework
  • 动态库.dylib.framework

静态库在链接时被复制到可执行文件中,而动态库在程序运行时由系统动态加载到内存中。需要特别注意的是,项目中如果使用了自制的动态库,不能被上传到 App Store。

三、静态库的制作和使用

1. 为什么要做静态库

静态库在保护核心技术和代码复用中有很大作用。例如国内的百度地图、友盟等提供的 SDK 就是静态库形式。动态库由于安全性和发布限制,多数情况下,我们会选择静态库。

2. 制作静态库的步骤

  1. 新建一个项目,如 Tools
  2. 创建一个类并实现简单的加法方法。
  3. 编译项目,分别为真机(arm)和模拟器(i386/x86_64)生成静态库。
  4. 将生成的 .a 文件和头文件拖入需要使用的项目中。

3. 静态库中的资源包使用

为了避免与主项目资源冲突,静态库中的图片资源可以使用 bundle。

  1. 创建一个 Bundle,并将图片资源添加其中。
  2. 创建一个类方法返回图片。
  3. 编译项目时会生成相应的 bundle 文件,在使用时需要将 .h.aXXX.bundle 一同导入。

4. 调试和发布版本

静态库有调试(Debug)和发布(Release)版本,调试版本包含完整的符号信息,未经过优化。发布版本则经过优化,体积更小,运行速度更快。在调试阶段使用 Debug 版,在发布阶段使用 Release 版。

5. 合并静态库

合并不同架构的静态库,以便在不同设备上使用:

lipo -create Debug-iphoneos/libTools.a Debug-iphonesimulator/libTools.a -output libTools.a

合并后的静态库会整合所有架构,利于调试和发布。

四、CPU架构

1. 常见报错

如果使用静态库时报错 Undefined symbols for architecture i386,说明静态库不支持该 CPU 架构。

2. CPU 架构列表

  • 模拟器架构
    • iPhone 4s 到 iPhone 5:i386
    • iPhone 5s 到 当前机型:x86_64
  • 真机场构
    • iPhone 3GS 到 iPhone 4s:armv7
    • iPhone 5 到 iPhone 5c:armv7s
    • iPhone 5s 到 当前机型:arm64

3. 检查静态库支持架构

lipo -info libExample.a

五、创建和使用静态库时的注意点

  1. 制作 .a 静态库时需包含头文件。
  2. 新建项目,添加静态库 target 进行调试。
  3. 编译过程中关注选择合适的 CPU 架构和适当的调试版本。
  4. 编译出来的静态库通过选择合适配置支持多种设备和 CPU 架构。

六、framework制作

在Xcode中制作framework的详细教程如下:

一、创建项目

  1. 打开Xcode:启动Xcode,选择“Create a new Xcode project”。
  2. 选择模板:在模板选择界面,选择“Framework & Library”模板,然后点击“Next”。
  3. 选择框架类型:在弹出的选项中选择“Cocoa Touch Framework”,并点击“Next”。
  4. 填写项目信息:填写工程的名字和其他相关信息,如组织名称、组织标识符等,然后点击“Next”。
  5. 选择保存路径:选择保存Framework的路径,并点击“Create”。

二、配置项目

  1. 设置Mach-O Type:在Xcode中,选择工程的主目录,进入“Build Settings”。搜索“Mach-O Type”,将其值设置为“Static Library”。

  2. 设置Product Module Name:搜索“Product Module Name”,将其值设置为Framework的名称,比如“MyFramework”。

  3. 设置其他构建选项

    • 搜索“Skip Install”,将其值设置为“YES”。
    • 搜索“Installation Directory”,将其值设置为“@rpath”。
    • 搜索“Always Embed Swift Standard Libraries”,如果项目使用了Swift,则将其值设置为“YES”。
    • 搜索“Base SDK”,选择为iOS。
    • 搜索“iOS Deployment Target”,设置最低支持版本。
    • 搜索“Build Active architecture only”,设置为NO,表示当前打包的.a支持所有的设备。
    • 搜索“excluded architectures”,根据需要进行配置,避免后期合并时模拟器和真机内容有重叠导致错误。
    • 搜索“User Script Sandboxing”,设置为NO,控制用户脚本对系统资源和用户数据的访问级别,设置为NO就不会去校验权限问题了。

三、添加源代码和头文件

  1. 创建文件夹:在工程中添加一个新的文件夹,用于存放Framework的源代码。
  2. 拖拽文件:将需要打包成framework静态库的文件资源等拖拽进该项目。
  3. 设置头文件暴露:将需要暴露给外部的代码文件拖拽到新建的文件夹中。在需要暴露给外部的代码文件上右键,选择“Target Membership”并勾选Framework的名称。或者,在“Build Phases”中的“Headers”部分,将需要暴露的头文件长按拖动到“Public”下面。

四、编译和验证

  1. 编译Framework:在Xcode中,选择菜单栏的“Product” -> “Build”,编译Framework。编译成功后,可以在工程的DerivedData目录下找到编译生成的Framework。
  2. 验证Framework:双击生成的Framework文件,在弹出的Finder窗口中,可以查看Framework的结构。确保所有需要暴露的头文件都已被正确包含。

五、导出和使用Framework

  1. 导出Framework文件

    • 真机架构:编译设备选择真机或无设备,通过Xcode左上角菜单栏“Product” -> “Build For” -> “Profiling”导出对应模式下的framework文件。
    • 模拟器架构:编译设备选择任一模拟器,然后重复上述“Build For”步骤即可。
  2. 合并真机和模拟器架构:打开终端,执行以下命令合并真机和模拟器架构的framework文件:

    lipo -create 模拟器下的.a 真机下的.a -output 新合并的静态库的存放路径
    

    例如:

    lipo -create /path/to/simulator/framework /path/to/device/framework -output /path/to/output/framework
    
  3. 使用Framework

    • 在需要使用Framework的项目中,选择“General”选项卡。
    • 在“Embedded Binaries”部分,点击“+”按钮,选择需要使用的Framework文件,点击“Add”。
    • 在需要使用Framework的代码文件中,使用#import或者@import导入Framework的头文件。
    • 在代码中使用Framework提供的功能。

通过以上步骤,就可以在Xcode中成功制作并使用一个自定义的framework了。这不仅可以提高代码的重用性,还能使项目结构更加清晰,便于管理和维护。

posted @   Mr.陳  阅读(1194)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
点击右上角即可分享
微信分享提示