亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

前言

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

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

效果如下:

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

顏色配置

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

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

{
 "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",
 }
}

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

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

對應的代碼如下,這里有個需要注意的地方是,加載配置文件的時候使用了文件讀寫鎖進行讀寫的鎖定操作,防止讀臟數(shù)據(jù)的發(fā)生,直到配置文件加載完成,釋放讀寫鎖,這時讀進程可以繼續(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)先級排序
 [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;
 
 // 加載默認配置
 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 {
 // 每一次新增一個配置文件,所有配置文件都得重新計算一次,這里有很多重復多余的工作
 [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) {
 // 十六進制字符串轉(zhuǎn)為UIColor
 UIColor *color = [UIColor yt_nullcolorWithHexString:obj];
 if (color) {
  [dictionary setObject:color forKey:key];
 } else {
  [dictionary setObject:obj forKey:key];
 }
 }];
}

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

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

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

/**
 獲取顏色值
 */
- (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;
 }
 
 ///看看是否有替補key
 if (colorObj == nil) {
 NSString *reserveKey = [_reserveKeyMap objectForKey:key];
 if (reserveKey) {
  colorObj = [self colorForKey:reserveKey isReserveKey:YES redirectCount:redirectCount];
 }
 }
 
 ///查看當前key 能否轉(zhuǎn)成 color
 if (colorObj == nil) {
 colorObj = [UIColor yt_colorWithHexString:key];
 }
 
 if ([colorObj isKindOfClass:[UIColor class]]) {
 ///如果是 重定向 或者 替補 key 的color 要設置到 當前 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)由管理者的,為了方便,定義一個顏色宏提供給客戶端使用

#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];

另外,因為顏色配置的key為字符串類型,直接使用字符串常量并不是個好辦法,所以把對應的字符串轉(zhuǎn)換為宏定義是一個相對好的辦法。第一個是方便使用,可以使用代碼提示;第二個是不容易出錯,特別是長的字符串;第三個也會一定程度上的提高效率。

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";

主題包管理

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

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

/**
 設置主題文件的路徑
 @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);
}

如何實施

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

優(yōu)化

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

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

附:讀寫鎖pthread_rwlock_t的使用

讀寫鎖是用來解決讀者寫者問題的,讀操作可以共享,寫操作是排他的,讀可以有多個在讀,寫只有唯一個在寫,同時寫的時候不允許讀。

具有強讀者同步和強寫者同步兩種形式

強讀者同步:當寫者沒有進行寫操作,讀者就可以訪問;

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

讀寫鎖的操作:

讀寫鎖的初始化:

        定義讀寫鎖:          pthread_rwlock_t  m_rw_lock;

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

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

讀寫鎖的銷毀:

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

        返回值:0,表示成功,非0表示錯誤碼

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

        阻塞式:

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

        非阻塞式:

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

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

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

      阻塞式:

                           函數(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ū)別:

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

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

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

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

讀寫鎖描述:

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

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

總結(jié)

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

相關(guān)文章

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

    用iOS模擬器安裝App的方法

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    iOS中使用NSURLConnection處理HTTP同步與異步請求

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

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

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

最新評論