======文档更新状态=====
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=============