IOS開發(fā)實用技巧(一)

1.調(diào)試技巧重寫description方法打印類的成員屬性
#import <objc/runtime.h>
-(NSString *)description{
    unsigned int count = 0;
    NSMutableString *str = [NSMutableString string];
    Ivar *ivars = class_copyIvarList([self class], &count);
    for(int i =0;i < count;i ++)
    {
        Ivar ivar = ivars[i];
        NSString *ivarName = [NSString stringWithCString:ivar_getName(ivar) encoding:NSUTF8StringEncoding];
        id value = [self valueForKey:ivarName];
        //如果是最后一個變量去掉","
        if (i == count -1) {
            [str appendFormat:@"%@=%@",ivarName,value];
        }else{
         [str appendFormat:@"%@=%@,",ivarName,value];
        }
    }
    free(ivars);
    return [NSString stringWithFormat:@"%@{%@}",[super description],str];
}

2.自動歸檔解檔

//存
- (void)encodeWithCoder:(NSCoder *)aCoder{
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([TXModel class], &count);
    for (int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];
        const char *name = ivar_getName(ivar);
        NSString *key = [NSString stringWithUTF8String:name];
        id value = [self valueForKey:key];
        [aCoder encodeObject:value forKey:key];
    }
    free(ivars);
}
//取
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
    if (self = [super init]) {
        unsigned int count = 0;
        Ivar *ivars = class_copyIvarList([TXModel class], &count);
        for (int i = 0; i < count; i++) {
            Ivar ivar = ivars[i];
            const char *name = ivar_getName(ivar);
            NSString *key = [NSString stringWithUTF8String:name];
            id value = [aDecoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
        free(ivars);
    }
    return self;
}
```
>注意:通過上面的幾個demo的演示,就不在此重復一些runtime的其他類似黑魔法了(獲取方法/屬性等等..)

3.攔截交換系統(tǒng)方法(NSObject加分類方法)
    用處:分類中最好是不能重寫父類方法的,這時候要實現(xiàn)全局修改某個系統(tǒng)方法加上自己的邏輯判斷,只能用交換系統(tǒng)的方法更好.
    還可以攔截系統(tǒng)奔潰.
```
@interface  UIView (MethodSwizzling)
/**
 *  交換對象方法
 */
+ (void)zh_swizzleInstanceSelector:(SEL)origSelector swizzleSelector:(SEL)swizzleSelector;
/**
 *  交換類方法
 */
+ (void)zh_swizzleClassSelector:(SEL)origSelector swizzleSelector:(SEL)swizzleSelector;
@end

@implementation  UIView (MethodSwizzling)

+ (void)zh_swizzleInstanceSelector:(SEL)origSelector swizzleSelector:(SEL)swizzleSelector {
    // 獲取原有方法
    Method origMethod = class_getInstanceMethod(self,origSelector);
    // 獲取交換方法
    Method swizzleMethod = class_getInstanceMethod(self,swizzleSelector);
    BOOL isAdd = class_addMethod(self, origSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (!isAdd) {
        method_exchangeImplementations(origMethod, swizzleMethod);
    }else {
        class_replaceMethod(self, swizzleSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
    }
}
+ (void)zh_swizzleClassSelector:(SEL)origSelector swizzleSelector:(SEL)swizzleSelector
{
    // 獲取原有方法
    Method origMethod = class_getClassMethod(self,origSelector);
    // 獲取交換方法
    Method swizzleMethod = class_getClassMethod(self,swizzleSelector);
    // 添加原有方法實現(xiàn)為當前方法實現(xiàn)
    BOOL isAdd = class_addMethod(self, origSelector, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
    if (!isAdd) {
        method_exchangeImplementations(origMethod, swizzleMethod);
    }
}
```
>注意:實現(xiàn)load類方法 --- 類被加載運行的時候就會調(diào)用
當類加載進內(nèi)存的時候調(diào)用,而且不管有沒有子類,都只會調(diào)用一次,在main函數(shù)之前調(diào)用

```
+ (void)load
{
   [self zh_swizzleInstanceSelector:@selector( setBackgroundColor:)swizzleSelector:@selector( setMyBackgroundColor:)];
}
- (void)setMyBackgroundColor:(UIColor *)color{
    NSLog(@"%s",__FUNCTION__);
    //此處沒有遞歸而是調(diào)用系統(tǒng)的setBackgroundColor
    [self setMyBackgroundColor:[UIColor orangeColor]];
}
```

4._cmd的一種巧妙用方法(分類中關(guān)聯(lián)屬性對象)

之前需要定義一個這樣的const void *key,_cmd 是隱藏的參數(shù),代表當前方法的 selector,可以代替這個key.
之前寫法:
```
const void *webCacheKEY = "webCache";
-(void)setCurrentURL:(NSString *)currentURL{
//關(guān)聯(lián)對象
    //參數(shù)1:要被關(guān)聯(lián)的對象
    //參數(shù)2:關(guān)聯(lián)的KEY
    //參數(shù)3:關(guān)聯(lián)的值
    //參數(shù)4:關(guān)聯(lián)策略(內(nèi)存引用)
    objc_setAssociatedObject(self, webCacheKEY, currentURL, OBJC_ASSOCIATION_COPY);
}
-(NSString *)currentURL{
    //參數(shù)1:要被關(guān)聯(lián)的對象
    //參數(shù)2:關(guān)聯(lián)的KEY
    return objc_getAssociatedObject(self, webCacheKEY);
}
```
之后寫法:
```
-(void)setCurrentURL:(NSString *)currentURL{
    objc_setAssociatedObject(self, _cmd, currentURL, OBJC_ASSOCIATION_COPY);
}

-(NSString *)currentURL{
    return objc_getAssociatedObject(self, _cmd);
}
```
5.背景漸變色
```
- (void)viewDidLoad {
    [super viewDidLoad];
    [self.view.layer addSublayer:[self backgroundLayer]];
}
//背景漸變色
-(CAGradientLayer *)backgroundLayer{
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = self.view.bounds;
    gradientLayer.colors = @[(__bridge id)[UIColor purpleColor].CGColor,(__bridge id)[UIColor redColor].CGColor];
    gradientLayer.startPoint = CGPointMake(0.5, 0);
    gradientLayer.endPoint = CGPointMake(0.5, 1);
    gradientLayer.locations = @[@0.65,@1];
    return gradientLayer;
}
```
6.調(diào)試代碼執(zhí)行時間
```
#define TICK   NSDate *startTime = [NSDate date];
#define TOCK   NSLog(@"Time: %f", -[startTime timeIntervalSinceNow]);
TICK
// 代碼塊
TOCK
```
7.程序啟動過程中各個階段所消耗的時間
   在工程的scheme中添加環(huán)境變量DYLD_PRINT_STATISTICS = 1,這樣在調(diào)試時,可以在控制臺打印出程序啟動過程中各個階段所消耗的時間。


8.KVC集合運算符
   KVC集合運算符允許在valueForKeyPath:方法中使用key path符號在一個集合中執(zhí)行方法。可以直接求出總數(shù)/最大值/最小值/平均值
```
@interface TestModel : NSObject
@property (nonatomic, assign) double price;
@end

- (void)viewDidLoad {
    [super viewDidLoad];
     NSArray *priceArray = @[@"1",@"2",@"3",@"4",@"5"];
     NSMutableArray *dataArray = [NSMutableArray array];
     for (NSInteger i = 0; i < priceArray.count; ++i) {
        TestModel *testModel = [[TestModel alloc] init];
        testModel.price = [priceArray[i] doubleValue];
        [dataArray addObject:testModel];
    }
    id count1 = [dataArray valueForKeyPath:@"@count"];     // 5
    id count2 = [dataArray valueForKeyPath:@"@sum.price"]; // 15
    id count3 = [dataArray valueForKeyPath:@"@avg.price"]; // 3
    id count4 = [dataArray valueForKeyPath:@"@max.price"]; // 5
    id count5 = [dataArray valueForKeyPath:@"@min.price"]; // 1
    NSLog(@"%@,%@,%@,%@,%@",count1,count2,count3,count4,count5);

    NSArray *array = [NSArray arrayWithObjects:@"2.0", @"2.3", @"3.0", @"4.0", @"10", nil];
    id sum = [array valueForKeyPath:@"@sum.floatValue"];
    id avg = [array valueForKeyPath:@"@avg.floatValue"];
    id max = [array valueForKeyPath:@"@max.floatValue"];
    id min = [array valueForKeyPath:@"@min.floatValue"];
    NSLog(@"%@,%@,%@,%@",sum,avg,max,min);
}
```
9.抗鋸齒的兩種方法
第一種:
```
    self.view.layer.allowsEdgeAntialiasing = YES;
```
 第二種:
```
    self.view.layer.borderColor = [UIColorclearColor].CGColor;
    self.view.layer.borderWidth = 1.f;
```
10.調(diào)節(jié)UINavigationBar的leftBarButtonItem離左邊的距離
```
    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"back-button-whiteArrow.png"] style:UIBarButtonItemStylePlain target:self action:@selector(logoutBarBtnPressed:)];
    UIBarButtonItem *fixedBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil];
    fixedBarButtonItem.width = -15;
    self.navigationItem.leftBarButtonItems = [NSArray arrayWithObjects:fixedBarButtonItem, buttonItem, nil];
```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容