久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

用Runtime的手段填充任意NSObject對象的nil屬性

 沒原創(chuàng)_去搜索 2015-08-31

前言

好久沒有寫東西了,忙啊,。

前段時間參加了一下我們?nèi)A科聯(lián)創(chuàng)的HackDay(本人在讀研=,。=,,目前在阿里實習(xí)),,作品是一款  實時在線對戰(zhàn)游戲 - 波波攢 ,(介紹請看  知乎 ) 

從iOS游戲客戶端(用的  SpriteKit )到后臺(  PHP CI + Node + SocketIO + MySQL )全是自己一個人倒騰出來的,,做了一把真正的全棧工程師,,爽啊~ 

后面會完善整個游戲,增加角色,、優(yōu)化啥的,,過上一段時間會上線的哈~

回到正文,本文主要介紹了怎么用Runtime的手段遍歷任意NSObject對象的所有property,,檢查其值是否是nil,,是的話根據(jù)其類型為其填充一個默認(rèn)值。 

Runtime畢竟是個“危險”的技術(shù),,本文的代碼只是個初步的嘗試,。

初衷

在做項目的過程中,總是會寫一大堆if、else語句去檢查對象的Property是否是nil,,如從服務(wù)器返回的JSON中缺少屬性,,導(dǎo)致Entity的某些值為空;或者創(chuàng)建的對象沒有對所有屬性做初始化等等,。寫多了覺得好煩啊=,。=所以想到本文的方法,嗯,,程序員總是懶的,。 

解決步驟

  1. 遍歷一個對象的所有屬性(默認(rèn)不包括父類屬性)。
  2. 判斷屬性是否是nil,。
  3. 為nil的屬性,獲取它的類型,。
  4. 根據(jù)類型設(shè)置初始值(如NSString可以設(shè)為空字符串,;NSNumber可以設(shè)為@0)

Runtime

OC是一門“動態(tài)”、“基于消息”的語言,,而Runtime就是利用OC的動態(tài)特性,,在運行時對程序做出“調(diào)整”的技術(shù)。有關(guān)Runtime的官方文檔,、網(wǎng)上的資料很多,,大家自學(xué)哈~

本文主要用了如下幾個Runtime的函數(shù): 

// 獲取類的所有Property
1. objc_property_t *class_copyPropertyList(Class cls, unsigned int *outCount)
// 獲取一個Property的變量名
2. const char *property_getName(objc_property_t property)
// 獲取一個Property的詳細(xì)類型表達(dá)字符串
3. const char *property_getAttributes(objc_property_t property)

示例

不好一塊一塊拆開說,直接上代碼: 

/**
 * 解析Property的Attributed字符串,,參考Stackoverflow
 */
static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    
    NSLog(@"%s", attributes);
    
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        // 非對象類型
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // 利用NSData復(fù)制一份字符串
            return (const char *) [[NSData dataWithBytes:(attribute + 1) length:strlen(attribute) - 1] bytes];
        // 純id類型
        } else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            return "id";
        // 對象類型
        } else if (attribute[0] == 'T' && attribute[1] == '@') {
            return (const char *) [[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "";
}

/**
 * 給對象的屬性設(shè)置默認(rèn)值
 */
void checkEntity(NSObject *object) {
    // 不同類型的字符串表示,,目前只是簡單檢查字符串、數(shù)字,、數(shù)組
    static const char *CLASS_NAME_NSSTRING;
    static const char *CLASS_NAME_NSNUMBER;
    static const char *CLASS_NAME_NSARRAY;
    
    // 初始化類型常量
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // "NSString"
        CLASS_NAME_NSSTRING =  NSStringFromClass([NSString class]).UTF8String;
        // "NSNumber
        CLASS_NAME_NSNUMBER = NSStringFromClass([NSNumber class]).UTF8String;
        // "NSArray"
        CLASS_NAME_NSARRAY = NSStringFromClass([NSArray class]).UTF8String;
    });
    
    @try {
        unsigned int outCount, i;
        // 包含所有Property的數(shù)組
        objc_property_t *properties = class_copyPropertyList([object class], &outCount);
        
        // 遍歷每個Property
        for (i = 0; i < outCount; i++) {
            // 取出對應(yīng)Property
            objc_property_t property = properties[i];
            // 獲取Property對應(yīng)的變量名
            NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
            // 獲取Property的類型名
            const char *propertyTypeName = getPropertyType(property);
            // 獲取Property的值
            id propertyValue = [object valueForKey:propertyName];
            
            // 值為空,,才設(shè)置默認(rèn)值
            if (!propertyValue) {
                // NSString
                if (strncmp(CLASS_NAME_NSSTRING, propertyTypeName, strlen(CLASS_NAME_NSSTRING)) == 0) {
                    [object setValue:@"" forKey:propertyName];
                }
                
                // NSNumber
                if (strncmp(CLASS_NAME_NSNUMBER, propertyTypeName, strlen(CLASS_NAME_NSNUMBER)) == 0) {
                    [object setValue:@0 forKey:propertyName];
                }
                
                // NSArray
                if (strncmp(CLASS_NAME_NSARRAY, propertyTypeName, strlen(CLASS_NAME_NSARRAY)) == 0) {
                    [object setValue:@[] forKey:propertyName];
                }
            }
        }
        
        // 別忘了釋放數(shù)組
        free(properties);
    } @catch (NSException *exception) {
        NSLog(@"Check Entity Exception: %@", [exception description]);
    }
}

重點 - 解析property_getAttributes函數(shù)的結(jié)果

在整個處理過程中,property_getAttributes函數(shù)是關(guān)鍵,,因為我們要首先確定Property的類型,,才能根據(jù)類型賦初值,但是property_getAttributes函數(shù)返回的字符串比較“晦澀難懂”:

如下定義的Property: 

@property (copy, nonatomic) NSString *name;
@property (strong, nonatomic) NSNumber *number;
@property (strong, nonatomic) NSArray *array;
@property (assign, nonatomic) NSInteger i;
@property (assign, nonatomic) CGFloat f;
@property (assign, nonatomic) char *cStr;

依次通過property_getAttributes獲取的結(jié)果是: 

T@"NSString",C,N,V_name
T@"NSNumber",&,N,V_number
T@"NSArray",&,N,V_array
Tq,N,V_i
Td,N,V_f
T*,N,V_cStr

參考  Declared Properties of Objective-C Runtime Programming Guide

我們大概可以知道,,T表示Type,,后面跟著@表示Cocoa對象類型,后面的表示Property的屬性,,如Copy,、strong等,然后就是變量名,。

所以getPropertyType函數(shù)的工作就是純粹的解析字符串,,獲取T@后面的類型名。

效果

例如我們有如下對象: 

@interface UserEntity : NSObject
@property (copy, nonatomic) NSString *name;
@property (strong, nonatomic) NSNumber *number;
@property (strong, nonatomic) NSArray *array;
@end

設(shè)置默認(rèn)值: 

UserEntity *userEntity = [UserEntity new];
// 檢查屬性,設(shè)置默認(rèn)值,。
checkEntity(userEntity);
// 使用...
NSLog(@"name: %@", userEntity.name);
NSLog(@"number: %@", userEntity.number);
NSLog(@"array: %@", userEntity.array);

輸出: 

2015-07-11 18:17:25.918 Common[6939:270543] name: 
2015-07-11 18:17:25.918 Common[6939:270543] number: 0
2015-07-11 18:17:25.918 Common[6939:270543] array: (
)

這樣,,一個對象的所有Property都有了初值。

總結(jié)

上面的例子只是個粗略的版本,,只是檢查了字符串,、數(shù)字、數(shù)組,,其實完全可以擴(kuò)展出很多功能,,如針對不同的類型,根據(jù)對象的類型,,設(shè)置不同的默認(rèn)初值等,,靠讀者你了~

Runtime是個好東西,但是別亂用啊=,。=


    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多