換膚-Runtime - (Obj-C)

上一篇文章介紹了通過UIImage分類的方式實(shí)現(xiàn)換膚功能,但是此方式有一定的局限性:
需要開發(fā)前就考慮到這個功能,如果前期沒有考慮到皮膚處理,開發(fā)中期或后期產(chǎn)品迭代,需求中添加這個功能,再去添加分類修改代碼效率就太低了.這種情況下就可以通過Runtime機(jī)制來交換方法.

exchangeImplementations.png

與基本換膚一樣,在視圖上通過ImageView顯示不同的圖片演示換膚功能,同時為了演示多界面同步換膚,設(shè)置一個TabBarController為根控制器,包含兩個子控制器,如圖:

界面搭建.png

原理與基礎(chǔ)換膚一樣,仍然需要添加一個UIImage分類,在Load方法中通過運(yùn)行時機(jī)制交換方法:

  • 首先導(dǎo)入頭文件<objc/objc.h>

  • 接下來通過運(yùn)行時機(jī)制交換imageNamed和jsImageNamed方法

// 1. 獲取對應(yīng)交換的方法
Method method1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
Method method2 = class_getClassMethod([UIImage class], @selector(jsImageNamed:));
// 2. 交換方法
method_exchangeImplementations(method1, method2);
  • 外界直接使用系統(tǒng)方法imageNamed就可以了,運(yùn)行時已經(jīng)交換了兩個方法的實(shí)現(xiàn)部分

#######需要注意的地方:
1.使用運(yùn)行時機(jī)制交換方法,在App整個生命周期都會交換
2.使用交換方法后,注意死循環(huán)問題:
在自定義的方法中,調(diào)用了系統(tǒng)imageNamed方法,就會造成死循環(huán)(運(yùn)行時交換的是兩個方法的實(shí)現(xiàn)部分,當(dāng)外界調(diào)用imageNamed的時候,實(shí)際執(zhí)行的JSImageNamed的實(shí)現(xiàn)部分,這樣方法內(nèi)部調(diào)用了自己),但這里又要使用系統(tǒng)方法imageNamed,所以要換成自定義的jsImageNamed方法就可以了

// 自定義方法,根據(jù)當(dāng)前皮膚設(shè)置圖片
+ (UIImage *)jsImageNamed:(NSString *)name{
    
    if (isNight) { // 夜間模式
        
        name = [NSString stringWithFormat:@"%@_night",name];
    }
    
    return [UIImage jsImageNamed:name];
}

完整代碼:
.h

#import <UIKit/UIKit.h>

@interface UIImage (JSSkin)

// 根據(jù)皮膚設(shè)置圖片
+ (UIImage *)jsImageNamed:(NSString *)name;

// 記錄皮膚
+ (void)saveSkinModeWithNight:(BOOL)night;

// 獲取皮膚設(shè)置
+ (BOOL)isNight;

@end

.m

#import "UIImage+JSSkin.h"
#import <objc/runtime.h>

@implementation UIImage (JSSkin)

// 夜間模式標(biāo)識
static bool isNight;

+ (void)load{
    
    // 獲取偏好設(shè)置中的皮膚模式
    isNight = [[NSUserDefaults standardUserDefaults] boolForKey:@"isNight"];
    
    // 使用運(yùn)行時機(jī)制交換方法 一旦交換,在App整個生命周期都會交換
    // 1. 獲取對應(yīng)交換的方法
    Method method1 = class_getClassMethod([UIImage class], @selector(imageNamed:));
    Method method2 = class_getClassMethod([UIImage class], @selector(jsImageNamed:));
    // 2. 交換方法
    method_exchangeImplementations(method1, method2);
    
}

// 自定義方法,根據(jù)當(dāng)前皮膚設(shè)置圖片
+ (UIImage *)jsImageNamed:(NSString *)name{
    
    if (isNight) { // 夜間模式
        
        name = [NSString stringWithFormat:@"%@_night",name];
    }
    
    return [UIImage jsImageNamed:name];
}

+ (void)saveSkinModeWithNight:(BOOL)night{
    
    // 賦值,記錄當(dāng)前皮膚狀態(tài)
    isNight = night;
    
    // 本地記錄狀態(tài)(偏好設(shè)置)
    [[NSUserDefaults standardUserDefaults] setBool:isNight forKey:@"isNight"];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
}

+ (BOOL)isNight{
    
    // 返回當(dāng)前皮膚狀態(tài)
    return isNight;
}

@end

外界調(diào)用:
控制器1

#import "PageOneViewController.h"
#import "UIImage+JSSkin.h"

@interface PageOneViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *imageView_1;
@property (weak, nonatomic) IBOutlet UIImageView *imageView_2;
@property (weak, nonatomic) IBOutlet UISwitch *nightModeSwitch;

@end

@implementation PageOneViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 獲取當(dāng)前皮膚模式,同步Switch狀態(tài)
    self.nightModeSwitch.on = [UIImage isNight];
    // 設(shè)置圖片
    self.imageView_1.image = [UIImage imageNamed:@"baby"];
    self.imageView_2.image = [UIImage imageNamed:@"girl"];
    
}

// Switch開關(guān)點(diǎn)擊事件
- (IBAction)nightModeSwitchClick:(UISwitch *)sender {
    
    // 本地化存儲(偏好設(shè)置)
    [UIImage saveSkinModeWithNight:sender.isOn];
    
    // 設(shè)置圖片
    self.imageView_1.image = [UIImage imageNamed:@"baby"];
    self.imageView_2.image = [UIImage imageNamed:@"girl"];
    
}

@end

控制器2

#import "PageTwoViewController.h"
#import "UIImage+JSSkin.h"

@interface PageTwoViewController ()

@property (strong, nonatomic) IBOutlet UIImageView *imageView_3;

@end

@implementation PageTwoViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    // 設(shè)置圖片
    self.imageView_3.image = [UIImage imageNamed:@"girl"];

}

@end

效果圖:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實(shí)現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,275評論 5 13
  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運(yùn)行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,821評論 7 64
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,724評論 19 139
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 843評論 0 2
  • 1. 前幾天去參加了高中同學(xué)的婚禮,看著曾經(jīng)一起上課一起吃飯的朋友都已嫁為人妻了,還是挺感慨的,主要是感慨時間過得...
    文長長閱讀 9,505評論 100 335

友情鏈接更多精彩內(nèi)容