iOS开发基础57-换肤功能与静态库开发指南
一、iOS 换肤功能
1. 换肤功能的思路
实现换肤功能的几点思路:
-
解决方案1:基于颜色的图片命名规范
- 问题1:每套图片的文件名必须遵循“颜色+名称.png”格式。
- 问题2:如果将某一图片应用到其他皮肤时会比较麻烦。
-
解决方案2:利用 Bundle
- 不同皮肤的图片文件保存在不同的 Bundle 中。
- 问题:平面设计师维护不方便。
-
解决方案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. 制作静态库的步骤
- 新建一个项目,如
Tools
。 - 创建一个类并实现简单的加法方法。
- 编译项目,分别为真机(arm)和模拟器(i386/x86_64)生成静态库。
- 将生成的
.a
文件和头文件拖入需要使用的项目中。
3. 静态库中的资源包使用
为了避免与主项目资源冲突,静态库中的图片资源可以使用 bundle。
- 创建一个 Bundle,并将图片资源添加其中。
- 创建一个类方法返回图片。
- 编译项目时会生成相应的 bundle 文件,在使用时需要将
.h
、.a
和XXX.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 4s 到 iPhone 5:
- 真机场构:
- iPhone 3GS 到 iPhone 4s:
armv7
- iPhone 5 到 iPhone 5c:
armv7s
- iPhone 5s 到 当前机型:
arm64
- iPhone 3GS 到 iPhone 4s:
3. 检查静态库支持架构
lipo -info libExample.a
五、创建和使用静态库时的注意点
- 制作
.a
静态库时需包含头文件。 - 新建项目,添加静态库 target 进行调试。
- 编译过程中关注选择合适的 CPU 架构和适当的调试版本。
- 编译出来的静态库通过选择合适配置支持多种设备和 CPU 架构。
六、framework制作
在Xcode中制作framework的详细教程如下:
一、创建项目
- 打开Xcode:启动Xcode,选择“Create a new Xcode project”。
- 选择模板:在模板选择界面,选择“Framework & Library”模板,然后点击“Next”。
- 选择框架类型:在弹出的选项中选择“Cocoa Touch Framework”,并点击“Next”。
- 填写项目信息:填写工程的名字和其他相关信息,如组织名称、组织标识符等,然后点击“Next”。
- 选择保存路径:选择保存Framework的路径,并点击“Create”。
二、配置项目
-
设置Mach-O Type:在Xcode中,选择工程的主目录,进入“Build Settings”。搜索“Mach-O Type”,将其值设置为“Static Library”。
-
设置Product Module Name:搜索“Product Module Name”,将其值设置为Framework的名称,比如“MyFramework”。
-
设置其他构建选项:
- 搜索“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就不会去校验权限问题了。
三、添加源代码和头文件
- 创建文件夹:在工程中添加一个新的文件夹,用于存放Framework的源代码。
- 拖拽文件:将需要打包成framework静态库的文件资源等拖拽进该项目。
- 设置头文件暴露:将需要暴露给外部的代码文件拖拽到新建的文件夹中。在需要暴露给外部的代码文件上右键,选择“Target Membership”并勾选Framework的名称。或者,在“Build Phases”中的“Headers”部分,将需要暴露的头文件长按拖动到“Public”下面。
四、编译和验证
- 编译Framework:在Xcode中,选择菜单栏的“Product” -> “Build”,编译Framework。编译成功后,可以在工程的DerivedData目录下找到编译生成的Framework。
- 验证Framework:双击生成的Framework文件,在弹出的Finder窗口中,可以查看Framework的结构。确保所有需要暴露的头文件都已被正确包含。
五、导出和使用Framework
-
导出Framework文件:
- 真机架构:编译设备选择真机或无设备,通过Xcode左上角菜单栏“Product” -> “Build For” -> “Profiling”导出对应模式下的framework文件。
- 模拟器架构:编译设备选择任一模拟器,然后重复上述“Build For”步骤即可。
-
合并真机和模拟器架构:打开终端,执行以下命令合并真机和模拟器架构的framework文件:
lipo -create 模拟器下的.a 真机下的.a -output 新合并的静态库的存放路径
例如:
lipo -create /path/to/simulator/framework /path/to/device/framework -output /path/to/output/framework
-
使用Framework:
- 在需要使用Framework的项目中,选择“General”选项卡。
- 在“Embedded Binaries”部分,点击“+”按钮,选择需要使用的Framework文件,点击“Add”。
- 在需要使用Framework的代码文件中,使用
#import
或者@import
导入Framework的头文件。 - 在代码中使用Framework提供的功能。
通过以上步骤,就可以在Xcode中成功制作并使用一个自定义的framework了。这不仅可以提高代码的重用性,还能使项目结构更加清晰,便于管理和维护。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!