基于AFNetworking封裝的網絡層(一站式解析數據)

代碼地址: https://github.com/huangxiongbiao12/BGNetworking

1、封裝AFNetworking基本請求方法

封裝原因:當AFNetworking的api改變的時候只需要更改封裝的方法,無需大面積改動代碼(不封裝直接用AFNetworking請求如果AFNetworking的api變化所有用的地方都需要變化)

代碼依賴了MBProgressHUD,顯示加載圖

封裝思路接口:
1、主要封裝了Get Post請求帶HUD和不帶HUD的另外一個可以選擇是否帶HUD的接口
2、將上傳圖片的單獨封裝
3、封裝了https加載證書驗證的方法,只需要設置cer文件的路徑名稱,以及是否需要https驗證

代碼如下:
api

#import <Foundation/Foundation.h>
#import "NetStatusData.h"

@interface HttpRequstData : NSObject

+ (void)getUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)getNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)postNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

+ (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
                             parameters:(nullable id)parameters
              constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
                               progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
                                success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
                                failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;

@end

實現

#import "HttpRequstData.h"

/**
 *  是否開啟https SSL 驗證
 *
 *  @return YES為開啟,NO為關閉
 */
#define openHttpsSSL YES
/**
 *  SSL 證書名稱,僅支持cer格式。“app.bishe.com.cer”,則填“app.bishe.com”
 */
#define certificate @"public"

typedef NS_ENUM(NSInteger,HttpType) {
    GET,
    POST
};

static int timeOut = 30;

@interface HttpRequstData ()
{
    NSString *_url;
    NSDictionary *_parameters;
   
}
@property(nonatomic,strong)UILabel *tipsLable;

@end

@implementation HttpRequstData

+(void)getUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
    [[NetStatusData shareNetStatus] checkNetStatus];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = timeOut;
    // 加上這行代碼,https ssl 驗證。
    if(openHttpsSSL)
    {
        [manager setSecurityPolicy:[self customSecurityPolicy]];
    }
    [MBProgressHUD showMessage:@"加載中..."];
     DDLog(@"parameters:%@",parameters);
    [manager GET:url parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        DDLog(@"====%@,%@==url:%@",responseObject,parameters,url);
        [MBProgressHUD hideHUD];
        //登陸成功===================================
        if ([responseObject[@"status"] isEqualToNumber:@500]) {
            [MBProgressHUD showSuccess:@"加載成功"];
            if (success) {
                success(responseObject);
            }
        }else{//登陸失敗=============================
            if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
                [MBProgressHUD showError:responseObject[@"data"]];
            }else{
                [MBProgressHUD showError:@"信息錯誤"];
            }
            NSError *error1;
            failure(error1);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //         [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
        [MBProgressHUD hideHUD];
        [MBProgressHUD showError:@"網絡異常"];
        DDLog(@"%s==error--%@",__func__,error);
        if (error) {
            failure(error);
        }

    }];
}

+(void)getNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
    [[NetStatusData shareNetStatus] checkNetStatus];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = timeOut;
    // 加上這行代碼,https ssl 驗證。
    if(openHttpsSSL)
    {
        [manager setSecurityPolicy:[self customSecurityPolicy]];
    }
    DDLog(@"parameters:%@",parameters);
    [manager GET:url parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        DDLog(@"====%@,%@==url:%@",responseObject,parameters,url);
         [MBProgressHUD hideHUD];
        //登陸成功===================================
        if ([responseObject[@"status"] isEqualToNumber:@500]) {
            if (success) {
                success(responseObject);
            }
        }else{//登陸失敗=============================
            if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
                [MBProgressHUD showError:responseObject[@"data"]];
            }else{
                [MBProgressHUD showError:@"信息錯誤"];
            }
            NSError *error1;
            failure(error1);
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //         [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
        DDLog(@"%s==error--%@",__func__,error);
        [MBProgressHUD hideHUD];
        [MBProgressHUD showError:@"網絡異常"];
        if (error) {
            failure(error);
        }
        
    }];
}

#pragma mark-------封裝請求
+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
    [[NetStatusData shareNetStatus] checkNetStatus];
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    manager.requestSerializer.timeoutInterval = timeOut;
    // 加上這行代碼,https ssl 驗證。
    if(openHttpsSSL)
    {
        [manager setSecurityPolicy:[self customSecurityPolicy]];
    }
    if (show) {
        [MBProgressHUD showMessage:@"加載中..."];
    }
    DDLog(@"parameters:%@==url:%@==",parameters,url);
    
    [manager POST:url parameters:parameters progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        DDLog(@"====%@,%@==url:%@===parameters:%@",responseObject,responseObject[@"data"],url,parameters);
        if (show) {
            [MBProgressHUD hideHUD];
        }
        //登陸成功===================================
        if ([responseObject[@"status"] isEqualToNumber:@500]) {
            if ([responseObject[@"data"] isKindOfClass:[NSArray class]]) {
                if ([responseObject[@"data"] count] < 1) {
                    //                    [MBProgressHUD showSuccess:@"沒有更多數據"];
                }else{
                    if (show) {
                        //                        [MBProgressHUD showSuccess:@"加載成功"];
                    }
                }
            }else{
                if (show) {
                    //                    [MBProgressHUD showSuccess:@"加載成功"];
                }
            }
            if (success) {
                success(responseObject);
            }
        }else{//登陸失敗=============================
            if ([responseObject[@"data"] isKindOfClass:[NSString class]]) {
                //                if (show) {
                [MBProgressHUD showError:responseObject[@"data"]];
                //                }
            }else{
                //                if (show) {
                [MBProgressHUD showError:@"信息錯誤"];
                //                }
            }
            NSError *error1;
            failure(error1);
        }
        
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        //         [[NetWorkingStausTipLabel shareNetWorkingStausTipLabel] showDuration:2.0];
        if (show) {
            [MBProgressHUD hideHUD];
        }
        //        [MBProgressHUD showError:@"請求失敗"];
        DDLog(@"%s==error--%@",__func__,error);
        if (error) {
            failure(error);
        }
    }];
}


+(void)postUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
    [self postUrl:url parameters:parameters showHUD:YES success:success failure:failure];
}

+(void)postNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure
{
    [self postUrl:url parameters:parameters showHUD:NO success:success failure:failure];
}


#pragma mark-------上傳圖片

+(NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters constructingBodyWithBlock:(void (^)(id<AFMultipartFormData>))block progress:(void (^)(NSProgress *))uploadProgress success:(void (^)(NSURLSessionDataTask *, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError *))failure {
    
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    // 加上這行代碼,https ssl 驗證。
    if(openHttpsSSL)
    {
        [manager setSecurityPolicy:[self customSecurityPolicy]];
    }
    return [manager POST:URLString parameters:parameters constructingBodyWithBlock:block progress:uploadProgress success:success failure:failure];
}

+(NSURLSessionDataTask *)POST:(NSString *)URLString parameters:(id)parameters constructingBodyWithBlock:(void (^)(id<AFMultipartFormData>))block success:(void (^)(NSURLSessionDataTask *, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError *))failure {
    return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
}

#pragma mark========https

+ (AFSecurityPolicy*)customSecurityPolicy
{
    // /先導入證書
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:certificate ofType:@"cer"];//證書的路徑
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    
    // AFSSLPinningModeCertificate 使用證書驗證模式
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
//    AFSSLPinningModeNone、AFSSLPinningModeCertificate
    // allowInvalidCertificates 是否允許無效證書(也就是自建的證書),默認為NO
    // 如果是需要驗證自建證書,需要設置為YES
    securityPolicy.allowInvalidCertificates = YES;
    
    //validatesDomainName 是否需要驗證域名,默認為YES;
    //假如證書的域名與你請求的域名不一致,需把該項設置為NO;如設成NO的話,即服務器使用其他可信任機構頒發的證書,也可以建立連接,這個非常危險,建議打開。
    //置為NO,主要用于這種情況:客戶端請求的是子域名,而證書上的是另外一個域名。因為SSL證書上的域名是獨立的,假如證書上注冊的域名是www.google.com,那么mail.google.com是無法驗證通過的;當然,有錢可以注冊通配符的域名*.google.com,但這個還是比較貴的。
    //如置為NO,建議自己添加對應域名的校驗邏輯。
    securityPolicy.validatesDomainName = NO;
    
    securityPolicy.pinnedCertificates = [[NSSet alloc] initWithObjects:certData,nil];
    return securityPolicy;
}

2、封裝網絡狀態監測

思路:用了一個單例,每次請求接口的時候調用小網絡狀態監測api
根據不同的網絡情況顯示提示

#import <Foundation/Foundation.h>

@interface NetStatusData : NSObject

@property(nonatomic,assign)AFNetworkReachabilityStatus status;//網絡狀態

+(NetStatusData*)shareNetStatus;

-(void)checkNetStatus;//檢查網絡狀態

@end
static NetStatusData *_netStatus = nil;

@implementation NetStatusData

+(NetStatusData *)shareNetStatus {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (!_netStatus) {
            _netStatus = [NetStatusData new];
        }
    });
    return _netStatus;
}

-(void)checkNetStatus {
    AFNetworkReachabilityManager *manager=[AFNetworkReachabilityManager sharedManager];
    __weak AFNetworkReachabilityManager *weakManager = manager;
    [manager startMonitoring];
    //檢測網絡狀態有網絡,網絡請求數據,沒網絡提示
    [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        self.status = status;
        if (!status) {//未連接
            UIWindow *window = [[UIApplication sharedApplication].windows lastObject];
            UILabel *tipsLable;
            if (!tipsLable) {
                tipsLable = [[UILabel alloc] initWithFrame:(CGRect){kScreenWidth/2,kScreenHeight/2+80,110,33}];
                tipsLable.textColor = [UIColor whiteColor];
                tipsLable.textAlignment = NSTextAlignmentCenter;
                tipsLable.centerX = window.centerX;
                tipsLable.backgroundColor = [UIColor blackColor];
                tipsLable.text = @"網絡未連接";
            }
            [window addSubview:tipsLable];
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [tipsLable removeFromSuperview];
            });
            
            return;
        }else{//連接請求數據
            //            [self requstData:type];
        }
        [weakManager stopMonitoring];
    }];
}

@end

3、數據解析層(核心思想)

注:利用基類做類別封裝請求,可以直接用模型請求接口,并且封裝解析過程。根據不同的模型及json類型動態解析數據。后期代碼免去解析代碼

代碼分為兩部分,一部分代碼解析,一部分數據請求

1、數據請求

#import <Foundation/Foundation.h>

@interface NSObject (Request)
//請求數據
+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;

+(void)requestNoHUDUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure;
//解析數據
+(id)parseData:(id)responseObject;
//對象轉json
-(NSDictionary*)toJson;
//獲取屬性的類型
+(NSString*)getPropertyType:(NSString*)property;
-(NSString*)getPropertyType:(NSString*)property;

@end
#import "NSObject+Request.h"
#import <objc/runtime.h>

@implementation NSObject (Request)

+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters showHUD:(BOOL)show success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
    [HttpRequstData postUrl:url parameters:parameters showHUD:show success:^(id responseObject) {
        id obj = [self parseData:responseObject[@"data"]];
        success(obj);
    } failure:^(NSError *error) {
        failure(error);
    }];
}

+(void)requestUrl:(NSString*)url parameters:(NSDictionary*)parameters success:(void(^)(id responseObject)) success failure:(void(^)(NSError *error)) failure {
    [self requestUrl:url parameters:parameters showHUD:YES success:success failure:failure];
}

+(void)requestNoHUDUrl:(NSString *)url parameters:(NSDictionary *)parameters success:(void (^)(id))success failure:(void (^)(NSError *))failure {
    [self requestUrl:url parameters:parameters showHUD:NO success:success failure:failure];
}

+(id)parseData:(id)responseObject {
    
    id obj;
    //單個對象
    if ([responseObject isKindOfClass:[NSDictionary class]]) {
        obj = [[self alloc]init];
        [obj setValuesForKeysWithDictionary:responseObject];
    }
    //        多個對象
    else if ([responseObject isKindOfClass:[NSArray class]]) {
        obj = [NSMutableArray new];
        for (NSDictionary *dic in responseObject) {
            id o = [[self alloc]init];
            [o setValuesForKeysWithDictionary:dic];
            [obj addObject:o];
        }
    }
    return obj;
}

-(NSDictionary *)toJson
{
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    unsigned  int count = 0;
    Ivar *ivars = class_copyIvarList(self.class, &count);
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        id value = [self valueForKey:key];
        if ([value isKindOfClass:[NSString class]]&&[(NSString*)value length]) {
            [params setValue:value forKey:key];
        }
    }
    return params;
}

#pragma mark-------//獲取屬性的類型

+(NSString *)getPropertyType:(NSString *)property {
    //獲取對象的類型objc_getClass("UserModel")
    objc_property_t p = class_getProperty(self, property.UTF8String);
  if (!p) {
        return nil;
    }
    const char *cname = property_getAttributes(p);
    DDLog(@"%s==",cname);
    // 2.成員類型
    NSString *attrs = @(property_getAttributes(p));
    NSUInteger dotLoc = [attrs rangeOfString:@","].location;
    NSString *code = nil;
    NSUInteger loc = 3;
    if (dotLoc == NSNotFound) { // 沒有,
        code = [attrs substringFromIndex:loc];
    } else {
        code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc-1)];
    }
    DDLog(@"%@===%@====",code,attrs);
    return code;
}

-(NSString *)getPropertyType:(NSString *)property {
    //獲取對象的類型objc_getClass("UserModel")
    objc_property_t p = class_getProperty(self.class, property.UTF8String);
  if (!p) {
        return nil;
    }
    const char *cname = property_getAttributes(p);
    DDLog(@"%s==",cname);
    // 2.成員類型
    NSString *attrs = @(property_getAttributes(p));
    NSUInteger dotLoc = [attrs rangeOfString:@","].location;
    NSString *code = nil;
    NSUInteger loc = 3;
    if (dotLoc == NSNotFound) { // 沒有,
        code = [attrs substringFromIndex:loc];
    } else {
        code = [attrs substringWithRange:NSMakeRange(loc, dotLoc - loc-1)];
    }
    DDLog(@"%@===%@====",code,attrs);
    return code;
}


@end
2、數據解析

思路:通過kvc解析數據,判斷json的key值是否是json和數組是的話進一步解析。不是的話直接賦值,解決復雜類型的json動態解析。
注意:數據字段的時候需要指明數據放的對象類型

使用時需要解析的模型類需要繼承Model類

/*
 *對象中含有的模型數據對應的對象名稱例如
 *@{
    @"statuses" : @"Status",===字段有statuses的數組含有的對象為Status類型
 *};
 */
@property(nonatomic,strong)NSDictionary *classInArrayDic;

代碼如下

#import <Foundation/Foundation.h>
#import "NSObject+Request.h"

@interface Model : NSObject<NSCoding,NSCopying>

//對象轉json
-(NSDictionary*)toJson;
/*
 *對象中含有的模型數據對應的對象名稱例如
 *@{
    @"statuses" : @"Status",===字段有statuses的數組含有的對象為Status類型
 *};
 */
@property(nonatomic,strong)NSDictionary *classInArrayDic;

@end
#import "Model.h"

@implementation Model

-(void)setValue:(id)value forKey:(NSString *)key{
    
    if ([value isKindOfClass:[NSNumber class]]) {
        [self setValue:[NSString stringWithFormat:@"%@",value] forKey:key];
    }else if ([value isKindOfClass:[NSArray class]]) {
        
    }else{
        if (!value||[value isKindOfClass:[NSNull class]]) {
            [super setValue:@"" forKey:key];
        }else{
            [super setValue:value forKey:key];
        }
    }
}

-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    
        if ([key isEqualToString:@"description"]) {
            [self setValue:value forKey:@"descriptionStr"];
        }else if ([key isEqualToString:@"id"]){
            [self setValue:value forKey:@"Id"];
        }else if([key isEqualToString:@"newPrice"]){
            [self setValue:value forKey:@"price"];
        }else if([key isEqualToString:@"code"]){
            [self setValue:value forKey:@"codePara"];
        }else{
            DDLog(@"沒有key==%@",key);
        }
}

-(void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues {
    for (NSString *key in keyedValues) {
        id value = keyedValues[key];
        //對象中含有對象數組
        if ([value isKindOfClass:[NSArray class]]) {
            if (![self.classInArrayDic objectForKey:key]) {
                DDLog(@"請給數組對象對應類型");
                continue;
            }
            //設置數組的值
            NSMutableArray *values = [NSMutableArray new];
            //取出數組含有對象類型
            Class ObjectType = NSClassFromString(self.classInArrayDic[key]);
            DDLog(@"%@",ObjectType);
            for (NSDictionary *dic in value) {
                 //獲取對象類型生成實例
                id obj = [[ObjectType alloc]init];
                [obj setValuesForKeysWithDictionary:dic];
                [values addObject:obj];
            }
            [self setValue:values forKey:key];
        }else if ([value isKindOfClass:[NSDictionary class]]) {//對象中含有對象
            //獲取對象的類型
            NSString *type = [self getPropertyType:key];
            if (type.length) {
                DDLog(@"請給對象對應類型");
                continue;
            }
            //獲取對象類型生成實例
            Class ObjectType = NSClassFromString(type);
            id obj = [[ObjectType alloc]init];
            [obj setValuesForKeysWithDictionary:value];
            [self setValue:obj forKey:key];
        }else {
            [self setValue:value forKey:key];
        }
    }
}

-(NSDictionary *)toJson
{
    NSMutableDictionary *params = [NSMutableDictionary dictionary];
    unsigned  int count = 0;
    Ivar *ivars = class_copyIvarList(self.class, &count);
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        id value = [self valueForKey:key];
        if ([value isKindOfClass:[NSString class]]&&[(NSString*)value length]) {
            [params setValue:value forKey:key];
        }
    }
    return params;
}

#pragma mark-------NSCoding,歸接檔協議,運行時

- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned  int count = 0;
    Ivar *ivars = class_copyIvarList(self.class, &count);
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        id value = [self valueForKey:key];
        [aCoder encodeObject:value forKey:key];
    }
    
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init]) {
        
        unsigned  int count = 0;
        Ivar *ivars = class_copyIvarList(self.class, &count);
        
        for (int i = 0; i < count; i++) {
            const char *cname = ivar_getName(ivars[i]);
            NSString *name = [NSString stringWithUTF8String:cname];
            NSString *key = [name substringFromIndex:1];
            id value = [aDecoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
    }
    return self;
}

-(id)copyWithZone:(NSZone *)zone {
    id copy = [[[self class] allocWithZone:zone] init];
    unsigned  int count = 0;
    Ivar *ivars = class_copyIvarList(self.class, &count);
    
    for (int i = 0; i < count; i++) {
        const char *cname = ivar_getName(ivars[i]);
        NSString *name = [NSString stringWithUTF8String:cname];
        NSString *key = [name substringFromIndex:1];
        id value = [self valueForKey:key];
        [copy setValue:value forKey:key];
    }
    return copy;
}


@end
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370

推薦閱讀更多精彩內容