欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS實(shí)現(xiàn)換膚功能的簡(jiǎn)單處理框架(附源碼)

 更新時(shí)間:2019年02月14日 09:37:26   作者:aron1992  
這篇文章主要給大家介紹了關(guān)于iOS實(shí)現(xiàn)換膚功能的簡(jiǎn)單處理框架,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

前言

換膚功能是在APP開發(fā)過程中遇到的比較多的場(chǎng)景,為了提供更好的用戶體驗(yàn),許多APP會(huì)為用戶提供切換主題的功能。主題顏色管理涉及到的的步驟有

  • 顏色配置
  • 使用顏色
  • UI元素動(dòng)態(tài)變更的能力
  • 動(dòng)態(tài)修改配置
  • 主題包管理
  • 如何實(shí)施
  • 優(yōu)化

效果如下:

DEMO代碼:https://gitee.com/dhar/iosdemos/tree/master/YTThemeManagerDemo

顏色配置

因?yàn)樯婕暗蕉喾N配置,所以以代碼的方式定義顏色實(shí)踐和維護(hù)的難度是比較高的,一種合適的方案是--顏色的配置是通過配置文件的形式進(jìn)行導(dǎo)入的。配置文件會(huì)經(jīng)過轉(zhuǎn)換步驟,最終形成代碼層級(jí)的配置,以全局的方式提供給各個(gè)模塊使用,這里會(huì)涉及到一個(gè)顏色管理者的概念,一般地這回事一個(gè)單例對(duì)象,提供全局訪問的接口。同一個(gè)APP中在不同的模塊中保存不同的主題顏色配置,在不同的層級(jí)中也可以存在不同的主題顏色配置,因?yàn)樯婕暗綄蛹?jí)間的配置差異,所以顏色的配置需要引入一個(gè)等級(jí)的概念,一般地較高層級(jí)顏色的配置等級(jí)是高于較低層級(jí)的,存在相同的配置較高層級(jí)的配置會(huì)覆蓋較低層級(jí)的配置。

我們采用的顏色配置的文件形如下面所示,為什么是在一個(gè)json文件的colorkey下面呢,是為了考慮到未來(lái)的擴(kuò)展性,如果不同的主題會(huì)涉及到一些尺寸值的差異化,我們可以添加dimensionskey進(jìn)行擴(kuò)展配置。

{
 "color": {
 "Black_A":"323232",
 "Black_AT":"323232",
 "Black_B":"888888",
 "Black_BT":"888888",

 "White_A":"ffffff",
 "White_AT":"ffffff",
 "White_AN":"ffffff",

 "Red_A":"ff87a0",
 "Red_AT":"ff87a0",
 "Red_B":"ff5073",
 "Red_BT":"ff5073",

 "Colour_A":"377ce4",
 "Colour_B":"6aaafa",
 "Colour_C":"ff8c55",
 "Colour_D":"ffa200",
 "Colour_E":"c4a27a",
 }
}

有了以上的配置,顏色配置的工作主要就是解析該配置文件,把配置保存在一個(gè)單例對(duì)象中即可,這部分主要的步驟如下:

  • 配置文件類表根據(jù)等級(jí)排序
  • 獲取每個(gè)配置文件中的配置,進(jìn)行保存
  • 通知外部主題顏色配置發(fā)生改變

對(duì)應(yīng)的代碼如下,這里有個(gè)需要注意的地方是,加載配置文件的時(shí)候使用了文件讀寫鎖進(jìn)行讀寫的鎖定操作,防止讀臟數(shù)據(jù)的發(fā)生,直到配置文件加載完成,釋放讀寫鎖,這時(shí)讀進(jìn)程可以繼續(xù)。

- (void)loadConfigWithFileName:(NSString *)fileName level:(NSInteger)level {
 if (fileName.length == 0) {
 return;
 }
 
 pthread_rwlock_wrlock(&_rwlock);
 __block BOOL finded = NO;
 [self.configFileQueue enumerateObjectsUsingBlock:^(YTThemeConfigFile *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
 if ([obj.fileName isEqualToString:fileName]) {
  finded = YES;
  *stop = YES;
 }
 }];
 if (!finded) {
 // 新增配置文件
 YTThemeConfigFile *file = [[YTThemeConfigFile alloc] init];
 file.fileName = fileName;
 file.level = level;
 [self.configFileQueue addObject:file];
 // 優(yōu)先級(jí)排序
 [self.configFileQueue sortUsingComparator:^NSComparisonResult(YTThemeConfigFile *_Nonnull obj1, YTThemeConfigFile *_Nonnull obj2) {
  if (obj1.level > obj2.level) {
  return NSOrderedDescending;
  }
  return NSOrderedAscending;
 }];
 [self setupConfigFilesContainDefault:YES];
 }
 pthread_rwlock_unlock(&_rwlock);
}

- (void)setupConfigFilesContainDefault:(BOOL)containDefault {
 NSMutableDictionary *defaultColorDict = nil, *currentColorDict = nil;
 
 // 加載默認(rèn)配置
 if (containDefault) {
 defaultColorDict = [NSMutableDictionary dictionary];
 [self loadConfigDataWithColorMap:defaultColorDict valueMap:nil isDefault:YES];
 
 self.defaultColorMap = defaultColorDict;
 }
 
 // 加載主題配置
 if (_themePath.length > 0) {
 currentColorDict = [NSMutableDictionary dictionary];
 [self loadConfigDataWithColorMap:currentColorDict valueMap:nil isDefault:NO];
 
 self.currentColorMap = currentColorDict;
 }
 
 // 發(fā)送主體顏色變更通知
 [self notifyThemeDidChange];
}

- (void)notifyThemeDidChange {
 NSArray *allActionObjects = self.actionMap.objectEnumerator.allObjects;
 for (YTThemeAction *action in allActionObjects) {
 [action notifyThemeDidChange];
 }
}

- (void)loadConfigDataWithColorMap:(NSMutableDictionary *)colorMap valueMap:(NSMutableDictionary *)valueMap isDefault:(BOOL)isDefault {
 // 每一次新增一個(gè)配置文件,所有配置文件都得重新計(jì)算一次,這里有很多重復(fù)多余的工作
 [self.configFileQueue enumerateObjectsUsingBlock:^(YTThemeConfigFile *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
 NSDictionary *dict = nil;
 if (isDefault) {
  dict = obj.defaultDict;
 } else {
  dict = obj.currentDict;
 }
 if (dict.count > 0) {
  [self loadThemeColorTo:colorMap from:dict]; // 將所有配置表中的color字段的數(shù)據(jù)都放到colorMap中
 }
 }];
}

- (void)loadThemeColorTo:(NSMutableDictionary *)dictionary from:(NSDictionary *)from {
 NSDictionary<NSString *, NSString *> *colors = from[@"color"];
 [colors enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
 // 十六進(jìn)制字符串轉(zhuǎn)為UIColor
 UIColor *color = [UIColor yt_nullcolorWithHexString:obj];
 if (color) {
  [dictionary setObject:color forKey:key];
 } else {
  [dictionary setObject:obj forKey:key];
 }
 }];
}

管理者處理處理配置之外,還需要暴露外部接口給客戶端使用,以用于獲取不同主題下對(duì)應(yīng)的顏色色值、圖片資源、尺寸信息等和主題相關(guān)的信息。比如我們會(huì)提供一個(gè)colorForKey方法獲取不同主題下的同一個(gè)key對(duì)應(yīng)的顏色色值,獲取色值的大致步驟如下:

  • 從當(dāng)前的主題配置中獲取
  • 從默認(rèn)的主題配置中獲取
  • 從預(yù)留的主題配置中獲取
  • 如果重定向的配置,遞歸處理
  • 以上步驟都完成還未找到返回默認(rèn)黑色

這里使用了讀寫鎖的寫鎖,如果同時(shí)有寫操作獲取了該鎖,讀取進(jìn)程會(huì)阻塞直到寫操作的完成釋放鎖。

/**
 獲取顏色值
 */
- (UIColor *)colorForKey:(NSString *)key {
 pthread_rwlock_rdlock(&_rwlock);
 UIColor *color = [self colorForKey:key isReserveKey:NO redirectCount:0];
 pthread_rwlock_unlock(&_rwlock);
 return color;
}

- (UIColor *)colorForKey:(NSString *)key isReserveKey:(BOOL)isReserveKey redirectCount:(NSInteger)redirectCount {
 if (key == nil) {
 return nil;
 }
 
 ///正常獲取色值
 id colorObj = [_currentColorMap objectForKey:key];
 if (colorObj == nil) {
 colorObj = [_defaultColorMap objectForKey:key];
 }
 
 if (isReserveKey && colorObj == nil) {
 return nil;
 }
 
 ///看看是否有替補(bǔ)key
 if (colorObj == nil) {
 NSString *reserveKey = [_reserveKeyMap objectForKey:key];
 if (reserveKey) {
  colorObj = [self colorForKey:reserveKey isReserveKey:YES redirectCount:redirectCount];
 }
 }
 
 ///查看當(dāng)前key 能否轉(zhuǎn)成 color
 if (colorObj == nil) {
 colorObj = [UIColor yt_colorWithHexString:key];
 }
 
 if ([colorObj isKindOfClass:[UIColor class]]) {
 ///如果是 重定向 或者 替補(bǔ) key 的color 要設(shè)置到 當(dāng)前 colorDict 里面
 // 重定向的配置形如:"Red_A":"Red_B",
 if (redirectCount > 0 || isReserveKey) {
  [_currentColorMap ?: _defaultColorMap setObject:colorObj forKey:key];
 }
 return colorObj;
 } else {
 if (redirectCount < 3) { // 重定向遞歸
  return [self colorForKey:colorObj isReserveKey:NO redirectCount:redirectCount + 1];
 } else {
  return [UIColor blackColor];
 }
 }
}

使用顏色

顏色的使用也是經(jīng)由管理者的,為了方便,定義一個(gè)顏色宏提供給客戶端使用

#define YTThemeColor(key) ([[YTThemeManager sharedInstance] colorForKey:key])

客戶端使用的代碼如下:

UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 200, 40)];
label.text = @"Text";
label.textColor = YTThemeColor(kCK_Red_A);
label.backgroundColor = YTThemeColor(kCK_Black_H);
[self.view addSubview:label];

另外,因?yàn)轭伾渲玫膋ey為字符串類型,直接使用字符串常量并不是個(gè)好辦法,所以把對(duì)應(yīng)的字符串轉(zhuǎn)換為宏定義是一個(gè)相對(duì)好的辦法。第一個(gè)是方便使用,可以使用代碼提示;第二個(gè)是不容易出錯(cuò),特別是長(zhǎng)的字符串;第三個(gè)也會(huì)一定程度上的提高效率。

YTColorDefine類的宏定義

// .h 中的聲明
///Black
FOUNDATION_EXTERN NSString *kCK_Black_A;
FOUNDATION_EXTERN NSString *kCK_Black_AT;
FOUNDATION_EXTERN NSString *kCK_Black_B;
FOUNDATION_EXTERN NSString *kCK_Black_BT;

// .m 中的定義
NSString *kCK_Black_A = @"Black_A";
NSString *kCK_Black_AT = @"Black_AT";
NSString *kCK_Black_B = @"Black_B";
NSString *kCK_Black_BT = @"Black_BT";

主題包管理

在實(shí)際的落地項(xiàng)目中,主題包管理涉及到的事項(xiàng)包括主題包下載和解壓和動(dòng)態(tài)加載主題包等內(nèi)容,最后的一步是更換主題配置文件所在的配置路徑,為了演示的方便,我們會(huì)把不同主題的資源放置在bundle中某一個(gè)特定的文件夾下,通過切換管理者中的主題路徑配置來(lái)達(dá)到切換主題的效果,和動(dòng)態(tài)下載更換主題的步驟是一樣的。

管理者提供一個(gè)設(shè)置主題配置的配置路徑的方法,在該方法中改變配置路徑的同時(shí),重新加載配置即可,代碼如下

/**
 設(shè)置主題文件的路徑
 @param themePath 文件的路徑
 */
- (void)setupThemePath:(NSString *)themePath {
 pthread_rwlock_wrlock(&_rwlock);
 
 _themePath = [themePath copy];
 
 self.currentColorMap = nil;
 
 if ([_themePath.lowercaseString isEqualToString:[[NSBundle mainBundle] resourcePath].lowercaseString]) {
 _themePath = nil;
 }
 
 self.currentThemePath = _themePath;
 
 for (int i = 0; i < self.configFileQueue.count; i++) {
 YTThemeConfigFile *obj = [self.configFileQueue objectAtIndex:i];
 [obj resetCurrentDict];
 }
 [self setupConfigFilesContainDefault:NO];
 
 pthread_rwlock_unlock(&_rwlock);
}

如何實(shí)施

以上的流程涉及到的只是iOS平臺(tái)下的一個(gè)技術(shù)解決方案,真實(shí)的實(shí)踐過程中會(huì)涉及到安卓平臺(tái)、Web頁(yè)面、UI出圖的標(biāo)注,這些是要進(jìn)行統(tǒng)一處理的,才能在各個(gè)端上有一致的體驗(yàn)。第一步就是制定合理的顏色規(guī)范,把規(guī)范同步給各個(gè)端的利益相關(guān)人員;第二部是UI出圖顏色是規(guī)范的顏色定義值,而不是比如#ffffff這樣的顏色,需要是比如White_A這樣規(guī)范的顏色定義值,這樣客戶端處理使用的就是White_A這個(gè)值,不用管在不同主題下不同的顏色表現(xiàn)形式。

優(yōu)化

loadConfigDataWithColorMap方法調(diào)用的優(yōu)化

如果模塊很多,每個(gè)模塊都會(huì)調(diào)用loadConfigWithFileName加載配置文件,那么loadConfigDataWithColorMap方法處理文件的時(shí)間復(fù)雜度是O(N*N),會(huì)重復(fù)處理很多多余的工作,理想的做法是底層保存一份公有的顏色配置,然后在APP層加載一份定制化的配置,在模塊中不用再加載主題配置文件,這樣會(huì)提高效率。

附:讀寫鎖pthread_rwlock_t的使用

讀寫鎖是用來(lái)解決讀者寫者問題的,讀操作可以共享,寫操作是排他的,讀可以有多個(gè)在讀,寫只有唯一個(gè)在寫,同時(shí)寫的時(shí)候不允許讀。

具有強(qiáng)讀者同步和強(qiáng)寫者同步兩種形式

強(qiáng)讀者同步:當(dāng)寫者沒有進(jìn)行寫操作,讀者就可以訪問;

強(qiáng)寫者同步:當(dāng)所有寫者都寫完之后,才能進(jìn)行讀操作,讀者需要最新的信息,一些事實(shí)性較高的系統(tǒng)可能會(huì)用到該所,比如定票之類的。

讀寫鎖的操作:

讀寫鎖的初始化:

        定義讀寫鎖:          pthread_rwlock_t  m_rw_lock;

        函數(shù)原型:              pthread_rwlock_init(pthread_rwlock_t * ,pthread_rwattr_t *);

        返回值:0,表示成功,非0為一錯(cuò)誤碼

讀寫鎖的銷毀:

        函數(shù)原型:             pthread_rwlock_destroy(pthread_rwlock_t* );

        返回值:0,表示成功,非0表示錯(cuò)誤碼

獲取讀寫鎖的讀鎖操作:分為阻塞式獲取和非阻塞式獲取,如果讀寫鎖由一個(gè)寫者持有,則讀線程會(huì)阻塞直至寫入者釋放讀寫鎖。

        阻塞式:

                            函數(shù)原型:pthread_rwlock_rdlock(pthread_rwlock_t*);

        非阻塞式:

                            函數(shù)原型:pthread_rwlock_tryrdlock(pthread_rwlock_t*);

       返回值: 0,表示成功,非0表示錯(cuò)誤碼,非阻塞會(huì)返回ebusy而不會(huì)讓線程等待

獲取讀寫鎖的寫鎖操作:分為阻塞和非阻塞,如果對(duì)應(yīng)的讀寫鎖被其它寫者持有,或者讀寫鎖被讀者持有,該線程都會(huì)阻塞等待。

      阻塞式:

                           函數(shù)原型:pthread_rwlock_wrlock(pthread_rwlock_t*);

      非阻塞式:

                           函數(shù)原型:pthread_rwlock_trywrlock(pthread_rwlock_t*);

       返回值: 0,表示成功

釋放讀寫鎖:

                         函數(shù)原型:pthread_rwlock_unlock(pthread_rwlock_t*);

總結(jié)(轉(zhuǎn)):

互斥鎖與讀寫鎖的區(qū)別:

當(dāng)訪問臨界區(qū)資源時(shí)(訪問的含義包括所有的操作:讀和寫),需要上互斥鎖;

當(dāng)對(duì)數(shù)據(jù)(互斥鎖中的臨界區(qū)資源)進(jìn)行讀取時(shí),需要上讀取鎖,當(dāng)對(duì)數(shù)據(jù)進(jìn)行寫入時(shí),需要上寫入鎖。

讀寫鎖的優(yōu)點(diǎn):

對(duì)于讀數(shù)據(jù)比修改數(shù)據(jù)頻繁的應(yīng)用,用讀寫鎖代替互斥鎖可以提高效率。因?yàn)槭褂没コ怄i時(shí),即使是讀出數(shù)據(jù)(相當(dāng)于操作臨界區(qū)資源)都要上互斥鎖,而采用讀寫鎖,則可以在任一時(shí)刻允許多個(gè)讀出者存在,提高了更高的并發(fā)度,同時(shí)在某個(gè)寫入者修改數(shù)據(jù)期間保護(hù)該數(shù)據(jù),以免任何其它讀出者或?qū)懭胝叩母蓴_。

讀寫鎖描述:

獲取一個(gè)讀寫鎖用于讀稱為共享鎖,獲取一個(gè)讀寫鎖用于寫稱為獨(dú)占鎖,因此這種對(duì)于某個(gè)給定資源的共享訪問也稱為共享-獨(dú)占上鎖。

有關(guān)這種類型問題(多個(gè)讀出者和一個(gè)寫入者)的其它說(shuō)法有讀出者與寫入者問題以及多讀出者-單寫入者鎖。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • 用iOS模擬器安裝App的方法

    用iOS模擬器安裝App的方法

    下面小編就為大家分享一篇用iOS模擬器安裝App的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2018-01-01
  • Swift 開發(fā)之懶加載的實(shí)例詳解

    Swift 開發(fā)之懶加載的實(shí)例詳解

    這篇文章主要介紹了Swift 開發(fā)之懶加載的實(shí)例詳解的相關(guān)資料,希望通過本文能幫助到大家,實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下
    2017-09-09
  • iOS中模態(tài)Model視圖跳轉(zhuǎn)和Push視圖跳轉(zhuǎn)的需求實(shí)現(xiàn)方法

    iOS中模態(tài)Model視圖跳轉(zhuǎn)和Push視圖跳轉(zhuǎn)的需求實(shí)現(xiàn)方法

    這篇文章主要介紹了iOS中模態(tài)Model視圖跳轉(zhuǎn)和Push視圖跳轉(zhuǎn)的需求實(shí)現(xiàn),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2016-12-12
  • iOS開發(fā)檢測(cè)是否開啟定位、是否允許消息推送等權(quán)限的實(shí)例

    iOS開發(fā)檢測(cè)是否開啟定位、是否允許消息推送等權(quán)限的實(shí)例

    下面小編就為大家分享一篇iOS開發(fā)檢測(cè)是否開啟定位、是否允許消息推送等權(quán)限的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2018-01-01
  • 一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

    一篇文章讓你看懂IOS中的block為何再也不需要WeakSelf弱引用

    這篇文章主要給大家介紹了關(guān)于IOS中block為何再也不需要WeakSelf弱引用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2018-01-01
  • 如何利用FutureBuilder提高開發(fā)效率

    如何利用FutureBuilder提高開發(fā)效率

    這篇文章主要給大家介紹了關(guān)于如何利用FutureBuilder提高開發(fā)效率的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • swift3.0網(wǎng)絡(luò)圖片緩存原理簡(jiǎn)析

    swift3.0網(wǎng)絡(luò)圖片緩存原理簡(jiǎn)析

    這篇文章主要為大家簡(jiǎn)析了swift3.0網(wǎng)絡(luò)圖片緩存原理,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • iOS Label實(shí)現(xiàn)文字漸變色效果

    iOS Label實(shí)現(xiàn)文字漸變色效果

    文字漸變色可以使整體的效果更上一個(gè)檔次,最近在開發(fā)中就遇到了這個(gè)需求,所以整理出來(lái),下面這篇文章主要給大家介紹了關(guān)于iOS Label實(shí)現(xiàn)文字漸變色效果的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。
    2017-05-05
  • iOS中使用NSURLConnection處理HTTP同步與異步請(qǐng)求

    iOS中使用NSURLConnection處理HTTP同步與異步請(qǐng)求

    NSURLConnection的作用現(xiàn)在已經(jīng)基本被NSURLSession所取代,所以我們簡(jiǎn)單了解下iOS中使用NSURLConnection處理HTTP同步與異步請(qǐng)求的方法即可:
    2016-07-07
  • iOS中g(shù)if圖的顯示方法示例

    iOS中g(shù)if圖的顯示方法示例

    這篇文章主要給大家介紹了關(guān)于iOS中g(shù)if圖的示的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)各位iOS開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06

最新評(píng)論