iOS:Objective-C(OC)實現自動化description方法的思路及程式碼範例

來源:互聯網
上載者:User

iOS:Objective-C(OC)實現自動化description方法的思路及程式碼範例
關鍵字:Objective-C OC description函數 自動列印屬性及屬性值 運行時枚舉成員變數基礎實現使用NSLog或po,Xcode預設調用對象的description方法,若沒實現,則列印對象的地址,不方便查看對象的狀態。特別地,在RESTful編程中,伺服器返回的JSON對象往往具有較多屬性,若每個對象建立一個類,並為這些類一一實現description方法,工作量大且是重複性工作,對我們碼農沒實質協助,還容易漏掉部分屬性。像這種重複性工作,還是由電腦去做更合適。 實現自動化description的基本思路是,基類實現此方法,子類只需按需定義屬性即可。 基類實現description的演算法是,通過運行時讀取對象運行時所屬的類(註:當使用KVO時,在有觀察者的情況下,運行時將為被觀察的類產生一個新類,再返回新類的類型,具體描述可參考筆者的iOS:KVO實現原理的簡單驗證對象及所有成員變數,再由KVC讀寫成員變數的值。 BaseModel.m////////////////////////////////////////////////////////////////////////////- (NSDictionary *)mapPropertiesToDictionary {// 用以儲存屬性(key)及其值(value)NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];// 擷取當前類物件類型Class cls = [self class];// 擷取類對象的成員變數列表,ivarsCount為成員個數uint ivarsCount = 0;Ivar *ivars = class_copyIvarList(cls, &ivarsCount);// 遍曆成員變數列表,其中每個變數為Ivar類型的結構體const Ivar *ivarsEnd = ivars + ivarsCount;for (const Ivar *ivarsBegin = ivars; ivarsBegin < ivarsEnd; ivarsBegin++) {Ivar const ivar = *ivarsBegin;// 擷取變數名NSString *key = [NSString stringWithUTF8String:ivar_getName(ivar)];/*若此變數聲明為屬性,則變數名帶底線首碼'_'比如 @property (nonatomic, copy) NSString *name;則 key = _name;為方便查看屬性變數,在此特殊處理掉底線首碼*/if ([key hasPrefix:@"_"]) key = [key substringFromIndex:1];// 擷取變數值id value = [self valueForKey:key];// 處理屬性未賦值屬性,將其轉換為null,若為nil,插入將導致程式異常[dictionary setObject:value ? value : [NSNull null]  forKey:key];}return dictionary;}枚舉屬性完成了。需要說明的是,由於業務中類層次只有兩層,故上述代碼不處理父類屬性。若有需要,可通過class_getSuperclass()方法枚舉父類成員變數,在遞迴父類時,遞迴出口為當前枚舉的類等於根類NSObject,即cls == [NSObject class]。剩下的是實現基類的description方法。 BaseModel.m////////////////////////////////////////////////////////////////////////////- (NSString *)description {NSMutableString *str = [NSMutableString string];NSString *className = NSStringFromClass([self class]);NSDictionary *dic = [self mapPropertiesToDictionary];[dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {[str appendFormat:@"%@ = %@\n", key, obj];}];return str;}至此,功能基本完成。子類只需繼承基類,在.h檔案中聲明屬性即可。 User.m ////////////////////////////////////////////////////////////////////////////#import "BaseModel.h" @interface UserState : BaseModel @property (nonatomic, copy) NSString *name; @end雖然功能實現了,前面的實現還有效能最佳化空間。 效能最佳化每次調用description,都要調用mapPropertiesToDictionary,顯然無此必要。故,最佳化思路是,在基類中維護一個靜態雜湊表,子類第一次使用description方法才調用mapPropertiesToDictionary,往後都從雜湊表中檢索已構造的屬性值字典。下面給出一種參考實現。 BaseModel.m////////////////////////////////////////////////////////////////////////////static NSMutableDictionary *modelsDescription = nil; // 在load或initialize方法中初始化雜湊表,在此為字典。+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{modelsDescription = [NSMutableDictionary dictionary];});} // 修改description構造字典處理- (NSString *)description {//...if (value) {dic = (NSDictionary *)value;} else {dic = [self mapPropertiesToDictionary];[modelsDescription setObject:dic forKey:className];}//...}關於根類NSObject的load與initialize之間的區別,下次再作講解。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.