OC学习_11_类型比较_KVC

======文档更新状态=====
2015-12-27:发布

==================

day11-[2015-12-24]
一、不同类型数据的比较
1.基本类型直接使用==
2.结构体逐一比较每个成员,或者利用字节对齐特性进行逐字节比较
3.OC对象,==比较的是地址,如果需要比较内容(属性、成员变量等),则需要重写isEqual:方法
A。原则:非nil、自反、对称、一致、传递
B。注意继承时的特殊性:在做类型判断时,不应该使用isKindOfClass:而是使用isMemberOfClass:
4.特殊类型的比较
A。字符串:应该使用isEqual:或isEqualToString:;而不应该使用==
B。包装类:NSNumber可以直接==比较

// 结构体的逐字节比较
//  main.m

#import <Foundation/Foundation.h>
/**
 *  一个通用的结构体变量比较函数
 *  前提:2个比较的结构体是相同类型
 *  原理:利用结构体的字节对齐特性,进行逐字节比较
 *
 *  @param p1  第一个结构体变量的首地址
 *  @param p2  第二个结构体变量的首地址
 *  @param len 结构体类型所占存储字节数
 *
 *  @return NO:不相等;YES:相等
 */
BOOL isEqualStruct(const void* p1,const void* p2,size_t len){
    const char* c1=(const char* )p1;
    const char* c2=(const char* )p2;
    for (int i=0; i<len; i++) {
        if ((*(c1+i))!=(*(c2+i))) {
            return NO;
        }
    }
    return YES;
}

typedef struct {
    char c;
    int n;
    char d;
}Demo;

int main_struct(int argc, const char * argv[]) {
    NSPoint pa={10,20};
    NSSize pb={10,20};
    NSLog(@"%d",isEqualStruct(&pa, &pb, sizeof(NSPoint)));

    Demo d1={'b',100};
    Demo d2={'b',100,0};
    NSLog(@"%d",isEqualStruct(&d1, &d2, sizeof(Demo)));
    return 0;
}
// 对象重写equal比较
//  YYBook.h

#import <Foundation/Foundation.h>

@interface YYBook : NSObject
@property (nonatomic,copy)NSString* title;
@property (nonatomic,assign)int price;
-(instancetype)initWithTitle:(NSString*)title price:(int)price;
+(instancetype)bookWithTitle:(NSString*)title price:(int)price;
@end
//  YYBook.m

#import "YYBook.h"

@implementation YYBook
-(instancetype)initWithTitle:(NSString *)title price:(int)price{
    if (self=[super init]) {
        self.title=title;
        self.price=price;
    }
    return self;
}

+(instancetype)bookWithTitle:(NSString *)title price:(int)price{
    return [[self alloc]initWithTitle:title price:price];
}

-(BOOL)isEqual:(id)object{
    //不为nil
    if (object==nil) {
        return NO;
    }
    //自反性
    if (self==object) {
        return YES;
    }
    //一致性:使用isMemberOfClass:代替isKindOfClass
    if (![object isMemberOfClass:[self class]]){
        return NO;
    }
    //逐一比较每个成员变量或属性
    return [self.title isEqual:[object title]] && self.price==[object price];
}
@end
//  test_book.m

#import "YYBook.h"
int main_book(){
    YYBook* b1=[YYBook bookWithTitle:@"iOS" price:10];
    YYBook* b2=[YYBook bookWithTitle:@"iOS" price:10];
    if (b1==b2) {
        NSLog(@"b1==b2");
    }

    if ([b1 isEqual:b2]) {
        NSLog(@"[b1 isEqual:b2]");
    }

    NSLog(@"b1==nil:%d",[b1 isEqual:nil]);//0
    NSLog(@"b1==b1:%d",[b1 isEqual:b1]);//1
    NSLog(@"b2==b1:%d",[b2 isEqual:b1]);//1

    NSLog(@"===============");
    YYBook* b3=b1;
    if (b1==b3) {
        NSLog(@"b1==b3");
    }

    if ([b1 isEqual:b2]) {
        NSLog(@"[b1 isEqual:b3]");
    }
    NSLog(@"b1==b3:%d",[b1 isEqual:b3]);//1
    return 0;
}
1.不同类型数据的比较
   对于简单类型,可以使用运算符==进行比较
   对于结构体,应该逐一比较其中的每个成员
   但是对于对象类型,则应该使用isEqual方法进行比较,且自定义类型需重写
   注意包装类、字符串等类型的特殊性
2.包装类/字符串的特殊性
   NSValue不应该使用==运算符
   NSNumber可以使用==运算符
   NSString视情况而定:采用相同方式创建的NSString对象可以使用==运算符;反之则不可以
   总之,系统提供的对象类型使用isEqual一定比==运算符正确


二、KVC
1.使用键值编码(Key Value Coding)的方式操纵对象的属性、成员变量
2.基本语法,赋值:setValue: forKey:
取值:valueForKey:
3.运行机制(以赋值为例,取值过程一样,只是调用的方法不同):
A。首先查找并执行与Key对应的属性的setXxx:
B。如果A找不到,找属性对应的成员变量(以下划线开头的),而且不管其访问权限
C。如果B找不到,找属性对应的不带下划线的成员变量,而且不管其访问权限
D。如果C找不到,调用setValue:forUndefinedKey:方法,该方法默认抛出异常;如果不想抛出异常,则可以重写方法
4.在给基本类型的属性赋值时,必须封装成OC对象;取值时得到的也是OC对象,可以通过拆包获取基本类型。
5.在给基本类型的属性赋值时,不允许赋nil,否则会调用setNilValueForKey:方法,默认抛出异常;如果不想抛出异常,可以重写该方法

//  YYPerson.h

#import <Foundation/Foundation.h>

@interface YYPerson : NSObject
{
    @private
    int height;
    int _height;
}
@property (nonatomic,copy)NSString* name;
@property (nonatomic,assign,setter=aaa:)int age;
-(void)printHeight;
@end
//  YYPerson.m

#import "YYPerson.h"

@implementation YYPerson
-(NSString *)description{
    return [NSString stringWithFormat:@"Person:%@,%d",_name,_age];
}
-(void)printHeight{
//    NSLog(@"_height:%d",_height);
    NSLog(@"height:%d",height);
}
//-(void)setAge:(int)age{
//    NSLog(@"setAge:%d",age);
//    _age=age;
//}

-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
    NSLog(@"Key %@ not founded!",key);
}

-(id)valueForUndefinedKey:(NSString *)key{
    NSLog(@"Key %@ not founded!",key);
    return nil;
}

-(void)setNilValueForKey:(NSString *)key{
    if ([key isEqual:@"age"]){
        _age=20;
    }
}
@end
//  test_kvc1.m

#import "YYPerson.h"
int main_kvc1(){
    YYPerson* p1=[YYPerson new];
    p1.name=@"mike";
    p1.age=20;
    NSLog(@"%@",p1);

    NSLog(@"=====KVC====");
    [p1 setValue:@"jerry" forKey:@"name"];
    [p1 setValue:@30 forKey:@"age"];
    NSLog(@"%@",p1);

    NSLog(@"p1.name:%@",[p1 valueForKey:@"name"]);
    NSLog(@"p1.age:%d",[[p1 valueForKey:@"age"] intValue]);

    NSLog(@"=====使用KVC给_height赋值======");
    NSLog(@"_height:%@",[p1 valueForKey:@"height"]);//0
    [p1 setValue:@199 forKey:@"height"];
    NSLog(@"_height:%@",[p1 valueForKey:@"height"]);//199
    [p1 printHeight];

    NSLog(@"=======抛出异常(未重写时)========");
    [p1 setValue:@"sss" forKey:@"sss"];

    NSLog(@"_height:%@",[p1 valueForKey:@"_height"]);
    //1.找方法:_height
    //2.找成员变量:__height
    //3.找成员变量:_height
    //4.valueForUndefinedKey:



    return 0;
}

//  test_kvc2.m
// 在给基本类型的属性赋值时,不允许赋nil,否则会调用setNilValueForKey:方法
// ,默认抛出异常;如果不想抛出异常,可以重写该方法
#import "YYPerson.h"
int main(){
    YYPerson* p1=[YYPerson new];
    [p1 setValue:nil forKey:@"name"];
    [p1 setValue:@33 forKey:@"age"];
    [p1 setValue:nil forKey:@"height"];
    NSLog(@"%@",p1);
    return 0;
}

=============EOF=============

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值