iOS開發(fā)·runtime+KVC實(shí)現(xiàn)多層字典模型轉(zhuǎn)換(多層數(shù)據(jù):模型嵌套模型,模型嵌套數(shù)組,數(shù)組嵌套模型)

本文實(shí)驗(yàn)Demo傳送門:DictToModelDemo

前言:將后臺(tái)JSON數(shù)據(jù)中的字典轉(zhuǎn)成本地的模型,我們一般選用部分優(yōu)秀的第三方框架,如SBJSON、JSONKit、MJExtension、YYModel等。但是,一些簡(jiǎn)單的數(shù)據(jù),我們也可以嘗試自己來實(shí)現(xiàn)轉(zhuǎn)換的過程。

更重要的是,有時(shí)候在iOS面試的時(shí)候,部分面試官會(huì)不僅問你某種場(chǎng)景會(huì)用到什么框架,更會(huì)問你如果要你來實(shí)現(xiàn)這個(gè)功能,你有沒有解決思路?所以,自己實(shí)現(xiàn)字典轉(zhuǎn)模型還是有必要掌握的。有了這個(gè)基礎(chǔ),在利用運(yùn)行時(shí)runtime的動(dòng)態(tài)特性,你也可以實(shí)現(xiàn)這些第三方框架。

筆者的KVC系列為:

1. 字典轉(zhuǎn)模型:KVC

當(dāng)對(duì)象的屬性很多的時(shí)候,我們可以利用KVC批量設(shè)置。

- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues;

但是KVC批量轉(zhuǎn)的時(shí)候,有個(gè)致命的缺點(diǎn),就是當(dāng)字典中的鍵,在對(duì)象屬性中找不到對(duì)應(yīng)的屬性的時(shí)候會(huì)報(bào)錯(cuò)。解決辦法是實(shí)現(xiàn)下面的方法:

//空的方法體也行
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}

需求:有一個(gè)排名列表頁面,這個(gè)頁面的每個(gè)排名對(duì)應(yīng)一個(gè)模型,這個(gè)模型從Plist轉(zhuǎn)換得到。那么實(shí)現(xiàn)的代碼如下所示:

  • 頭文件
#import <Foundation/Foundation.h>

@interface GloryListModel : NSObject

//圖標(biāo)
@property (nonatomic, copy) NSString *icon;
//標(biāo)題
@property (nonatomic, copy) NSString *title;
//目標(biāo)控制器
@property (nonatomic, copy) NSString *targetVC;
//菜單編號(hào)
@property (nonatomic, copy) NSString *menuCode;

+ (instancetype)gloryListModelWithDict:(NSDictionary *)dict;

+ (NSArray<GloryListModel *> *)gloryListModelsWithPlistName:(NSString *)plistName;

@end
  • 實(shí)現(xiàn)文件
#import "GloryListModel.h"

@implementation GloryListModel

//kvc實(shí)現(xiàn)字典轉(zhuǎn)模型
- (instancetype)initWithDict:(NSDictionary *)dict{
    if (self = [super init]) {
        [self setValuesForKeysWithDictionary:dict];
    }
    return self;
}

//防止與后臺(tái)字段不匹配而造成崩潰
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{}

+ (instancetype)gloryListModelWithDict:(NSDictionary *)dict;{
    return [[self alloc]initWithDict:dict];
}

+ (NSArray<GloryListModel *> *)gloryListModelsWithPlistName:(NSString *)plistName;{
    //獲取路徑
    NSString *path = [[NSBundle mainBundle]pathForResource:plistName ofType:@"plist"];
    //讀取plist
    NSArray *dictArr = [NSArray arrayWithContentsOfFile:path];
    //字典轉(zhuǎn)模型
    NSMutableArray *modelArr = [NSMutableArray array];
    [dictArr enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL * _Nonnull stop) {
        [modelArr addObject:[self gloryListModelWithDict:dict]];
    }];
    return modelArr.copy;
}

@end

1.2 KVC字典轉(zhuǎn)模型弊端

弊端:必須保證,模型中的屬性和字典中的key一一對(duì)應(yīng)。
如果不一致,就會(huì)調(diào)用[<Status 0x7fa74b545d60> setValue:forUndefinedKey:]
報(bào)key找不到的錯(cuò)。

分析:模型中的屬性和字典的key不一一對(duì)應(yīng),系統(tǒng)就會(huì)調(diào)用setValue:forUndefinedKey:報(bào)錯(cuò)。

解決:重寫對(duì)象的setValue:forUndefinedKey:,把系統(tǒng)的方法覆蓋,
就能繼續(xù)使用KVC,字典轉(zhuǎn)模型了。

- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
}

2. 字典轉(zhuǎn)模型:Runtime

  • 思路1:利用運(yùn)行時(shí),首先要遍歷參數(shù)字典, 如果我們獲取得屬性列表中包含了字典中的 key,就利用 KVC 方法賦值,然后就完成了字典轉(zhuǎn)模型的操作。

  • 思路2:利用運(yùn)行時(shí),遍歷模型中所有屬性,根據(jù)模型的屬性名,去字典中查找key,取出對(duì)應(yīng)的值,給模型的屬性賦值,然后就完成了字典轉(zhuǎn)模型的操作。

至于實(shí)現(xiàn)途徑,可以提供一個(gè)NSObject分類,專門字典轉(zhuǎn)模型,以后所有模型都可以通過這個(gè)分類轉(zhuǎn)。

2.1 先遍歷被轉(zhuǎn)換的字典

  • 分類實(shí)現(xiàn):NSObject+EnumDictOneLevel.m
#import "NSObject+EnumDictOneLevel.h"
#import <objc/runtime.h>

const char *kCMPropertyListKey1 = "CMPropertyListKey1";

@implementation NSObject (EnumDictOneLevel)

+ (instancetype)cm_modelWithDict1:(NSDictionary *)dict
{
    /* 實(shí)例化對(duì)象 */
    id model = [[self alloc]init];
    
    /* 使用字典,設(shè)置對(duì)象信息 */
    /* 1. 獲得 self 的屬性列表 */
    NSArray *propertyList = [self cm_objcProperties];
    
    /* 2. 遍歷字典 */
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        
        /* 3. 判斷 key 是否字 propertyList 中 */
        if ([propertyList containsObject:key]) {
            
            // KVC字典轉(zhuǎn)模型
            if (obj) {
                /* 說明屬性存在,可以使用 KVC 設(shè)置數(shù)值 */
                [model setValue:obj forKey:key];
            }
        }
        
    }];
    
    /* 返回對(duì)象 */
    return model;
}

+ (NSArray *)cm_objcProperties
{
    /* 獲取關(guān)聯(lián)對(duì)象 */
    NSArray *ptyList = objc_getAssociatedObject(self, kCMPropertyListKey1);
    
    /* 如果 ptyList 有值,直接返回 */
    if (ptyList) {
        return ptyList;
    }
    /* 調(diào)用運(yùn)行時(shí)方法, 取得類的屬性列表 */
    /* 成員變量:
     * class_copyIvarList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 方法:
     * class_copyMethodList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 屬性:
     * class_copyPropertyList(__unsafe_unretained Class cls, unsigned int *outCount)
     * 協(xié)議:
     * class_copyProtocolList(__unsafe_unretained Class cls, unsigned int *outCount)
     */
    unsigned int outCount = 0;
    /**
     * 參數(shù)1: 要獲取得類
     * 參數(shù)2: 雷屬性的個(gè)數(shù)指針
     * 返回值: 所有屬性的數(shù)組, C 語言中,數(shù)組的名字,就是指向第一個(gè)元素的地址
     */
    /* retain, creat, copy 需要release */
    objc_property_t *propertyList = class_copyPropertyList([self class], &outCount);
    
    NSMutableArray *mtArray = [NSMutableArray array];
    
    /* 遍歷所有屬性 */
    for (unsigned int i = 0; i < outCount; i++) {
        /* 從數(shù)組中取得屬性 */
        objc_property_t property = propertyList[i];
        /* 從 property 中獲得屬性名稱 */
        const char *propertyName_C = property_getName(property);
        /* 將 C 字符串轉(zhuǎn)化成 OC 字符串 */
        NSString *propertyName_OC = [NSString stringWithCString:propertyName_C encoding:NSUTF8StringEncoding];
        [mtArray addObject:propertyName_OC];
    }
    
    /* 設(shè)置關(guān)聯(lián)對(duì)象 */
    /**
     *  參數(shù)1 : 對(duì)象self
     *  參數(shù)2 : 動(dòng)態(tài)添加屬性的 key
     *  參數(shù)3 : 動(dòng)態(tài)添加屬性值
     *  參數(shù)4 : 對(duì)象的引用關(guān)系
     */
    
    objc_setAssociatedObject(self, kCMPropertyListKey1, mtArray.copy, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    /* 釋放 */
    free(propertyList);
    return mtArray.copy;
    
}

@end
  • 模型:PersonModel.h
#import <Foundation/Foundation.h>

@interface PersonModel : NSObject

@property (nonatomic, copy) NSString *iconStr;

@property (nonatomic, copy) NSString *showStr;

@end
  • 調(diào)用
NSDictionary *dict = @{
                           @"iconStr":@"小明",
                           @"showStr":@"這是我的第一條心情"
                           };
    PersonModel *testPerson = [PersonModel cm_modelWithDict1:dict];
    // 測(cè)試數(shù)據(jù)
    NSLog(@"%@",testPerson);
  • 運(yùn)行驗(yàn)證

2.2 先遍歷模型的成員變量數(shù)組

  • 實(shí)現(xiàn)分類:NSObject+EnumArr.m
#import "NSObject+EnumArr.h"
#import <objc/message.h>

@implementation NSObject (EnumArr)

/*
 * 把字典中所有value給模型中屬性賦值,
 * KVC:遍歷字典中所有key,去模型中查找
 * Runtime:根據(jù)模型中屬性名去字典中查找對(duì)應(yīng)value,如果找到就給模型的屬性賦值.
 */
// 字典轉(zhuǎn)模型
+ (instancetype)modelWithDict:(NSDictionary *)dict
{
    // 創(chuàng)建對(duì)應(yīng)模型對(duì)象
    id objc = [[self alloc] init];
    
    
    unsigned int count = 0;
    
    // 1.獲取成員屬性數(shù)組
    Ivar *ivarList = class_copyIvarList(self, &count);
    
    // 2.遍歷所有的成員屬性名,一個(gè)一個(gè)去字典中取出對(duì)應(yīng)的value給模型屬性賦值
    for (int i = 0; i < count; i++) {
        
        // 2.1 獲取成員屬性
        Ivar ivar = ivarList[i];
        
        // 2.2 獲取成員屬性名 C -> OC 字符串
        NSString *ivarName = [NSString stringWithUTF8String:ivar_getName(ivar)];
        
        // 2.3 _成員屬性名 => 字典key
        NSString *key = [ivarName substringFromIndex:1];
        
        // 2.4 去字典中取出對(duì)應(yīng)value給模型屬性賦值
        id value = dict[key];
        
        
        // 獲取成員屬性類型
        NSString *ivarType = [NSString stringWithUTF8String:ivar_getTypeEncoding(ivar)];
        
        // 二級(jí)轉(zhuǎn)換,字典中還有字典,也需要把對(duì)應(yīng)字典轉(zhuǎn)換成模型
        //
        // 判斷下value,是不是字典
        if ([value isKindOfClass:[NSDictionary class]] && ![ivarType containsString:@"NS"]) { //  是字典對(duì)象,并且屬性名對(duì)應(yīng)類型是自定義類型
            // user User
            
            // 處理類型字符串 @\"User\" -> User
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"@" withString:@""];
            ivarType = [ivarType stringByReplacingOccurrencesOfString:@"\"" withString:@""];
            // 自定義對(duì)象,并且值是字典
            // value:user字典 -> User模型
            // 獲取模型(user)類對(duì)象
            Class modalClass = NSClassFromString(ivarType);
            
            // 字典轉(zhuǎn)模型
            if (modalClass) {
                // 字典轉(zhuǎn)模型 user
                value = [modalClass modelWithDict:value];
            }
            
            // 字典,user
            //            NSLog(@"%@",key);
        }
        
        // 三級(jí)轉(zhuǎn)換:NSArray中也是字典,把數(shù)組中的字典轉(zhuǎn)換成模型.
        // 判斷值是否是數(shù)組
        if ([value isKindOfClass:[NSArray class]]) {
            // 判斷對(duì)應(yīng)類有沒有實(shí)現(xiàn)字典數(shù)組轉(zhuǎn)模型數(shù)組的協(xié)議
            if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
                
                // 轉(zhuǎn)換成id類型,就能調(diào)用任何對(duì)象的方法
                id idSelf = self;
                
                // 獲取數(shù)組中字典對(duì)應(yīng)的模型
                NSString *type =  [idSelf arrayContainModelClass][key];
                
                // 生成模型
                Class classModel = NSClassFromString(type);
                NSMutableArray *arrM = [NSMutableArray array];
                // 遍歷字典數(shù)組,生成模型數(shù)組
                for (NSDictionary *dict in value) {
                    // 字典轉(zhuǎn)模型
                    id model =  [classModel modelWithDict:dict];
                    [arrM addObject:model];
                }
                
                // 把模型數(shù)組賦值給value
                value = arrM;
                
            }
        }
        
        // 2.5 KVC字典轉(zhuǎn)模型
        if (value) {
            
            [objc setValue:value forKey:key];
        }
    }
    
    
    // 返回對(duì)象
    return objc;
    
}

@end
  • 第1層模型:各個(gè)屬性與字典對(duì)應(yīng)
  • Status.h
#import <Foundation/Foundation.h>
#import "NSObject+EnumArr.h"

@class PersonModel;

@interface Status : NSObject <ModelDelegate>

@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) PersonModel *person;
@property (nonatomic, strong) NSArray *cellMdlArr;

@end
  • 第1層模型:實(shí)現(xiàn)文件需要指明數(shù)組里面裝的類名
  • Status.m
#import "Status.h"

@implementation Status

+ (NSDictionary *)arrayContainModelClass
{
    return @{@"cellMdlArr" : @"CellModel"};
}

@end

  • 第2層模型:第2層模型作為第一層模型的自定義類的屬性
  • PersonModel.h
#import <Foundation/Foundation.h>

@interface PersonModel : NSObject
@property (nonatomic, copy) NSString *iconStr;
@property (nonatomic, copy) NSString *showStr;

@end
  • 第2層模型:第2層模型作為第一層模型的數(shù)組類型的屬性
  • CellModel.h
#import <Foundation/Foundation.h>

@interface CellModel : NSObject

@property (nonatomic, copy) NSString *stateStr;
@property (nonatomic, copy) NSString *partnerStr;

@end
  • 將被轉(zhuǎn)換的字典
  • 運(yùn)行驗(yàn)證

2.3 對(duì)2.1的改進(jìn):2.1無法對(duì)多層數(shù)據(jù)進(jìn)行轉(zhuǎn)換

思路:可以模仿2.2中的遞歸,對(duì)2.1進(jìn)行改進(jìn):模型中,除了為數(shù)組屬性添加數(shù)組元素對(duì)應(yīng)的類名映射字典,還要為模型屬性對(duì)應(yīng)的類名添加映射字典。這是因?yàn)椋瑥淖值浔闅v出來的key無法得知自定義類型的屬性的類名。

  • Status.m
+ (NSDictionary *)dictWithModelClass
{
    return @{@"person" : @"PersonModel"};
}
  • NSObject+EnumDict.m
#import "NSObject+EnumDict.h"

//導(dǎo)入模型
#import "Status.h"
#import <objc/runtime.h>

@implementation NSObject (EnumDict)

const char *kCMPropertyListKey = "CMPropertyListKey";

+ (instancetype)cm_modelWithDict:(NSDictionary *)dict
{
    /* 實(shí)例化對(duì)象 */
    id model = [[self alloc]init];
    
    /* 使用字典,設(shè)置對(duì)象信息 */
    /* 1. 獲得 self 的屬性列表 */
    NSArray *propertyList = [self cm_objcProperties];
    
    /* 2. 遍歷字典 */
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        
        /* 3. 判斷 key 是否字 propertyList 中 */
        if ([propertyList containsObject:key]) {
            
            // 獲取成員屬性類型
            // 類型經(jīng)常變,抽出來
            NSString *ivarType;
            
            if ([obj isKindOfClass:NSClassFromString(@"__NSCFString")]) {
                ivarType = @"NSString";
            }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFArray")]){
                ivarType = @"NSArray";
            }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFNumber")]){
                ivarType = @"int";
            }else if ([obj isKindOfClass:NSClassFromString(@"__NSCFDictionary")]){
                ivarType = @"NSDictionary";
            }
            
            // 二級(jí)轉(zhuǎn)換,字典中還有字典,也需要把對(duì)應(yīng)字典轉(zhuǎn)換成模型
            // 判斷下value,是不是字典
            if ([obj isKindOfClass:NSClassFromString(@"__NSCFDictionary")]) { //  是字典對(duì)象,并且屬性名對(duì)應(yīng)類型是自定義類型
                // value:user字典 -> User模型
                // 獲取模型(user)類對(duì)象
                NSString *ivarType = [Status dictWithModelClass][key];
                Class modalClass = NSClassFromString(ivarType);
                
                // 字典轉(zhuǎn)模型
                if (modalClass) {
                    // 字典轉(zhuǎn)模型 user
                    obj = [modalClass cm_modelWithDict:obj];
                }
                
            }
            
            // 三級(jí)轉(zhuǎn)換:NSArray中也是字典,把數(shù)組中的字典轉(zhuǎn)換成模型.
            // 判斷值是否是數(shù)組
            if ([obj isKindOfClass:[NSArray class]]) {
                // 判斷對(duì)應(yīng)類有沒有實(shí)現(xiàn)字典數(shù)組轉(zhuǎn)模型數(shù)組的協(xié)議
                if ([self respondsToSelector:@selector(arrayContainModelClass)]) {
                    
                    // 轉(zhuǎn)換成id類型,就能調(diào)用任何對(duì)象的方法
                    id idSelf = self;
                    
                    // 獲取數(shù)組中字典對(duì)應(yīng)的模型
                    NSString *type =  [idSelf arrayContainModelClass][key];
                    
                    // 生成模型
                    Class classModel = NSClassFromString(type);
                    NSMutableArray *arrM = [NSMutableArray array];
                    // 遍歷字典數(shù)組,生成模型數(shù)組
                    for (NSDictionary *dict in obj) {
                        // 字典轉(zhuǎn)模型
                        id model =  [classModel cm_modelWithDict:dict];
                        [arrM addObject:model];
                    }
                    
                    // 把模型數(shù)組賦值給value
                    obj = arrM;
                    
                }
            }
            
            // KVC字典轉(zhuǎn)模型
            if (obj) {
                /* 說明屬性存在,可以使用 KVC 設(shè)置數(shù)值 */
                [model setValue:obj forKey:key];
            }
        }
        
    }];
    
    /* 返回對(duì)象 */
    return model;
}
  • 調(diào)用
// 解析Plist文件
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"statuses.plist" ofType:nil];
    NSDictionary *statusDict = [NSDictionary dictionaryWithContentsOfFile:filePath];

    // 獲取字典數(shù)組
    NSArray *dictArr = statusDict[@"statuses"];
    NSMutableArray *statusArr = [NSMutableArray array];

    // 遍歷字典數(shù)組
    for (NSDictionary *dict in dictArr) {

        Status *status = [Status cm_modelWithDict:dict];

        [statusArr addObject:status];
    }
    NSLog(@"%@",statusArr);
  • 運(yùn)行驗(yàn)證
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評(píng)論 6 546
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,814評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評(píng)論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評(píng)論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,779評(píng)論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,109評(píng)論 1 330
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評(píng)論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,287評(píng)論 0 291
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,799評(píng)論 1 338
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,515評(píng)論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,750評(píng)論 1 375
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,933評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評(píng)論 1 296
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,492評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,703評(píng)論 2 380

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

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,519評(píng)論 8 265
  • 引導(dǎo) 對(duì)于從事 iOS 開發(fā)人員來說,所有的人都會(huì)答出「 Runtime 是運(yùn)行時(shí) 」,什么情況下用 Runtim...
    Winny_園球閱讀 4,229評(píng)論 3 75
  • 對(duì)于從事 iOS 開發(fā)人員來說,所有的人都會(huì)答出【runtime 是運(yùn)行時(shí)】什么情況下用runtime?大部分人能...
    夢(mèng)夜繁星閱讀 3,732評(píng)論 7 64
  • 題記:借用此刻火車廣播里的聲音,旅行分兩種,一種是為了到達(dá)終點(diǎn),一種是把視線和心靈留在路上。 2017.02.25...
    菜鳥張大海Flying閱讀 606評(píng)論 2 1
  • 爆竹聲中一歲除, 春風(fēng)送暖入屠蘇。 千門萬戶瞳瞳日, 總把新桃換舊符。 1、過年的起源 春福齊至,年味正濃。 過年...
    愛蹭鞋底的螞蟻閱讀 1,214評(píng)論 7 9