iOS 高級開發(fā)_ Runtime --- 項(xiàng)目實(shí)戰(zhàn)篇

上篇主要是runtime的理論基礎(chǔ)(地址請戳這里),但是具體到項(xiàng)目中的時(shí)候很少會(huì)想到使用runtime來解決問題,本文主要根據(jù)筆者在項(xiàng)目中的某些需求,將使用runtime的某些場景記錄下來。

1 修改UITextField中placeholder的顏色以及文字大小

項(xiàng)目需求:textFiled為鏤空顯示父視圖的背景色,placeholder的顏色為白色,切字體字號為22px

1.1 解決問題思路

查看UITextField的屬性發(fā)現(xiàn)并沒有相關(guān)設(shè)置的屬性,使用runtime遍歷UITextField的屬性遍歷,并通過次變量修改placeholder的顏色和字體大小.

 unsigned int count;
    Ivar *ivarList = class_copyIvarList([UITextField class], &count);
    
    for (int i = 0 ; i < count; i++) {
        Ivar ivar = ivarList[i];
        
        NSString *name = [NSString stringWithUTF8String:ivar_getName(ivar)];
        //將第一個(gè)字符截取掉,獲得屬性名
        NSString *propertyName = [name substringFromIndex:1];

        //前面為成員變量,后面為屬性名
        NSLog(@"%@:%@",name,propertyName);
        
    }

查看控制臺打印結(jié)果(可以通過command+F搜索):

控制臺結(jié)果,部分未截圖
1.2 解決問題
 UITextField *textFiled = [[UITextField alloc]initWithFrame:CGRectMake(0, 200, self.view.frame.size.width, 40)];
    textFiled.backgroundColor = [UIColor clearColor];
    textFiled.layer.borderColor = [UIColor whiteColor].CGColor;
    textFiled.layer.borderWidth = 1;
    textFiled.layer.cornerRadius = 4;
    textFiled.placeholder = @"我是重生的占位符";
    
    [textFiled setValue:[UIColor whiteColor] forKeyPath:@"_placeholderLabel.textColor"];
    [textFiled setValue:[UIFont systemFontOfSize:11] forKeyPath:@"_placeholderLabel.font"];
    
    [self.view addSubview:textFiled];
1.3 效果展示
模擬器展示效果

但是該屬性變量屬于蘋果的私有API,使用該方法上線有可能會(huì)被拒,慎用.

2 項(xiàng)目中navigationBar的backItem不顯示文字

需求:項(xiàng)目中的大部分navigationBar的backItem不需要文字,只需要返回箭頭.

2.1 在不需要backItem文字的視圖控制器被push之前,設(shè)置backItem
UIBarButtonItem *backItem = [[UIBarButtonItem alloc]init];
    backItem.title = @"";
    self.navigationItem.backBarButtonItem = backItem;

設(shè)置該方法需要注意兩點(diǎn):需要在Push之前這是backBarButtonItem,否則無效;必須初始化一個(gè)新的UIBarButtonItem對象,設(shè)置其title為空并賦值,直接設(shè)置backBarButtonItem.title無效
頁面多的話,可以設(shè)置BaseController在其中設(shè)置,新生成的Controller繼承即可.

2.2 使用runtime解決

但是總覺的方法一這個(gè)不是解決問題的完美方法,想找到一個(gè)完美實(shí)現(xiàn)該需求且一勞永逸的方法。
使用category為UINavigationController增加擴(kuò)展方法

//在程序啟動(dòng)時(shí),使用runtime交換系統(tǒng)與自定義的方法
+(void)load{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method originalMethod = class_getInstanceMethod(self, @selector(backBarButtonItem));
        
        Method customMethod = class_getInstanceMethod(self, @selector(CM_BackBarButtonItem));
        method_exchangeImplementations(originalMethod, customMethod);
    });
}

static char CMCustomBackBarButtonKey;

-(UIBarButtonItem *)CM_BackBarButtonItem{
    UIBarButtonItem *item = [self CM_BackBarButtonItem];
    if (item) {
        return item;
    }
    item = objc_getAssociatedObject(self, &CMCustomBackBarButtonKey);
    if (!item) {
        item = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:NULL];
        objc_setAssociatedObject(self, &CMCustomBackBarButtonKey, item, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return item;
}
2.3 效果展示
展示效果

3 字體適配

項(xiàng)目中字體適配是很常見的情況,主要適配6p機(jī)型,常見的適配方法是在設(shè)置字體大小的時(shí)候乘以一個(gè)宏定義比例,該方法需要在每次設(shè)置字體的時(shí)候都要乘以比例,比較繁瑣.
runtime可以通過自定義的方法替換系統(tǒng)方法,因此又想到了runtime

3.1 解決思路:

需要設(shè)置字體大小的控件為UILabel和UIButton,通過分類分別為兩個(gè)類擴(kuò)展方法,自定義方法在子視圖加載之前重新設(shè)置控件的字體大小(通過判斷是否為6p乘以一個(gè)自定義的比例)

3.2 解決方法:
@implementation UIButton (Common)
+ (void)load {
    //方法交換應(yīng)該被保證,在程序中只會(huì)執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL systemSel = @selector(willMoveToSuperview:);
        SEL swizzSel = @selector(CM_WillMoveToSuperview:);
        Method systemMethod = class_getInstanceMethod([self class], systemSel);
        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
        
        //首先動(dòng)態(tài)添加方法,實(shí)現(xiàn)是被交換的方法,返回值表示添加成功還是失敗
        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));
        if (isAdd) {
            //如果成功,說明類中不存在這個(gè)方法的實(shí)現(xiàn)
            //將被交換方法的實(shí)現(xiàn)替換到這個(gè)并不存在的實(shí)現(xiàn)
            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
        } else {
            //否則,交換兩個(gè)方法的實(shí)現(xiàn)
            method_exchangeImplementations(systemMethod, swizzMethod);
        }
        
    });
}

- (void)CM_WillMoveToSuperview:(UIView *)newSuperview {
    
    [self CM_WillMoveToSuperview:newSuperview];
    //    if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
    //        return;
    //    }
    if (self) {
//不需要適配的,通過設(shè)置tag值跳過
        if (self.tag != 10086) {
            self.titleLabel.font = [UIFont systemFontOfSize:self.titleLabel.font.pointSize*SizeScale];
        } else {
                   }
    }
}

@end

UILable同樣可以使用替換系統(tǒng)的方法實(shí)現(xiàn)字體的適配.

效果就不展示,具體大家可以自己運(yùn)行在模擬器查看。

3.3 設(shè)計(jì)優(yōu)化

將UILabel的分類和UIButton的分類合并寫在一個(gè)類里面。

.h文件

.m文件

/**
 button的字體適配
 */
@implementation UIButton (Common)
+ (void)load {
    //方法交換應(yīng)該被保證,在程序中只會(huì)執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL systemSel = @selector(willMoveToSuperview:);
        SEL swizzSel = @selector(CM_WillMoveToSuperview:);
        Method systemMethod = class_getInstanceMethod([self class], systemSel);
        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
        
        //首先動(dòng)態(tài)添加方法,實(shí)現(xiàn)是被交換的方法,返回值表示添加成功還是失敗
        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));
        if (isAdd) {
            //如果成功,說明類中不存在這個(gè)方法的實(shí)現(xiàn)
            //將被交換方法的實(shí)現(xiàn)替換到這個(gè)并不存在的實(shí)現(xiàn)
            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
        } else {
            //否則,交換兩個(gè)方法的實(shí)現(xiàn)
            method_exchangeImplementations(systemMethod, swizzMethod);
        }
        
    });
}

- (void)CM_WillMoveToSuperview:(UIView *)newSuperview {
    
    [self CM_WillMoveToSuperview:newSuperview];
    //    if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
    //        return;
    //    }
    if (self) {
        if (self.tag != 10086) {
            self.titleLabel.font = [UIFont systemFontOfSize:self.titleLabel.font.pointSize*SizeScale];
        } else {
                   }
    }
}

@end

#pragma mark --- 字體設(shè)置
@implementation UILabel (Common)

+ (void)load {
    
    //方法交換應(yīng)該被保證,在程序中只會(huì)執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL systemSel = @selector(willMoveToSuperview:);
        SEL swizzSel = @selector(CM_WillMoveToSuperview:);
        Method systemMethod = class_getInstanceMethod([self class], systemSel);
        Method swizzMethod = class_getInstanceMethod([self class], swizzSel);
        
        //首先動(dòng)態(tài)添加方法,實(shí)現(xiàn)是被交換的方法,返回值表示添加成功還是失敗
        BOOL isAdd = class_addMethod(self, systemSel, method_getImplementation(swizzMethod), method_getTypeEncoding(swizzMethod));
        if (isAdd) {
            //如果成功,說明類中不存在這個(gè)方法的實(shí)現(xiàn)
            //將被交換方法的實(shí)現(xiàn)替換到這個(gè)并不存在的實(shí)現(xiàn)
            class_replaceMethod(self, swizzSel, method_getImplementation(systemMethod), method_getTypeEncoding(systemMethod));
        } else {
            //否則,交換兩個(gè)方法的實(shí)現(xiàn)
            method_exchangeImplementations(systemMethod, swizzMethod);
        }
        
    });
}

- (void)CM_WillMoveToSuperview:(UIView *)newSuperview {
    
    [self CM_WillMoveToSuperview:newSuperview];
    //    if ([self isKindOfClass:NSClassFromString(@"UIButtonLabel")]) {
    //        return;
    //    }
    if (self) {
        if (self.tag != 10086) {
            self.font = [UIFont systemFontOfSize:self.font.pointSize*SizeScale];
        } else {
        }
    }
}

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

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

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