方法的系统适配
- 以日历类为例:NSCalendar对象的创建有几种方法,但是那些新的方法是支持高版本系统的,也就是说,在低版本系统中是没有这些方法的,那么如果要满足在不同的系统中调用不同的方法,需要做一个方法的适配,如下
NSCalendar *calendar = nil;
if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
} else {
calendar = [NSCalendar currentCalendar];
}
respondsToSelector和instancesRespondToSelector
respondsToSelector:方法的作用:判断左边对象能否调用右边的方法
instancesRespondToSelector:方法的作用:判断左边类的实例对象能否调用右边的方法
[@"jack" respondsToSelector:@selector(length)] // 判断是否有-length这个对象方法
[@"jack" length]
[NSString respondsToSelector:@selector(length)] // 判断是否有+length这个类方法
[NSString length]
[NSString instancesRespondToSelector:@selector(length)] // 判断是否有-length这个对象方法
[@"" length]
比较系统版本
//获取当前系统的版本
NSString *version = [UIDevice currentDevice].systemVersion;
/*
NSOrderedAscending 升序(右边 > 左边)
NSOrderedSame 相等、相同
NSOrderedDescending 降序(右边 < 左边)
*/
//方式一
if ([version compare:@"8.0"] != NSOrderedAscending) { // iOS系统版本 >= 8.0
}
//方式二
if (version.doubleValue >= 8.0) { // iOS系统版本 >= 8.0
}
//比较Foundation框架的版本号
if (NSFoundationVersionNumber >= NSFoundationVersionNumber_iOS_8_0) { // iOS系统版本 >= 8.0
}
//其他一
if ([@"" respondsToSelector:@selector(boundingRectWithSize:options:attributes:context:)]) { // iOS系统版本 >= 7.0
}
//其他二
if (NSClassFromString(@"UIAlertController")) { // iOS系统版本 >= 8.0
}
"==" "isEqualToString" "isEqual"的区别
"=="是比较两个对象的内存地址
"isEqualToString"计较的是两个字符串的内容
"isEqual"默认情况下是比较两个对象的内存地址,但是有一些系统自带的类(比如Foundation中的NSString)重写了这个方法,改变了这个方法的判断规则(一般改为比较两个对象的内容,不是内存地址)
Foundation中的一般规则:如果系统中的某个类重写了isEqual这个方法改变其判断规则,那么这个类会提供一个isEqualToXXX方法用来提示开发者isEqual被重写过了,例如: NSString中重写了isEqual,将这个方法的判断规则由判断两个对象的内存地址改为比较两个对象的内容,并且提供一个isEqualToString方法
NSString *string1 = @"jack";
NSString *string2 = [NSString stringWithFormat:@"jack"];
NSLog(@"string1 == string2 -> %zd", string1 == string2); // 0
NSLog(@"[string1 isEqualToString:string2] -> %zd", [string1 isEqualToString:string2]); // 1
NSLog(@"[string1 isEqual:string2] -> %zd", [string1 isEqual:string2]); // 1
NSString *string1 = @"jack";
NSString *string2 = @"jack";
NSLog(@"%p %p", string1, string2);
NSLog(@"string1 == string2 -> %zd", string1 == string2); // 1
NSLog(@"[string1 isEqualToString:string2] -> %zd", [string1 isEqualToString:string2]); // 1
NSLog(@"[string1 isEqual:string2] -> %zd", [string1 isEqual:string2]); // 1
重写自定义类的isEqual方法(以Person类为例)
/*
一旦重写了isEqual:方法,最好重写hash方法,而且要遵守以下原则:
1.isEqual:返回YES的2个对象,hash值一定要一样
2.hash值一样的2个对象,isEqual:返回不一定是YES
*/
- (NSUInteger)hash
{
return self.age + self.no + self.name.hash ;
}
- (BOOL)isEqual:(XMGPerson *)object
{
return [self isEqualToPerson:object];
}
- (BOOL)isEqualToPerson:(XMGPerson *)person
{
// 如果是完全相同的对象,就省去后面的判断
if (self == person) return YES;
// 如果object的类型不对,就不需要比较
if (![person isKindOfClass:self.class]) return NO;
// 基本数据类型
BOOL result = (self.age == person.age && self.no == person.no);
if (result == NO) return result;
// 对象类型
if (self.name || person.name) {
if (![self.name isEqual:person.name]) return NO;
}
if (self.car || person.car) {
if (![self.car isEqual:person.car]) return NO;
}
return YES;
}
XMGPerson *p1 = [[XMGPerson alloc] init];
p1.age = 20;
p1.no = 30;
NSString *string1 = [NSString stringWithFormat:@"222"];
NSString *string2 = @"222";
NSArray *array = @[@"111", @"333", string2, string1];
NSLog(@"%zd", [array containsObject:p1]);
NSLog(@"%zd", [array indexOfObject:string1]);
[array containsObject:]和[array indexOfObject:]的底层实现思路
- (BOOL)containsObject:(id)anObject
{
if (anObject == nil) return NO;
for (id obj in self) {
if ([anObject isEqual:obj]) return YES;
}
return NO;
}
- (NSUInteger)indexOfObject:(id)anObject
{
if (anObject == nil) return NSNotFound;
NSUInteger index = 0;
for (id obj in self) {
if ([anObject isEqual:obj]) return index;
index++;
}
return NSNotFound;
}