一、比较大小
一个枚举
typedef NS_ENUM(NSInteger, NSComparisonResult) {
NSOrderedAscending = -1L,
NSOrderedSame,
NSOrderedDescending
};
这个枚举, 主要用于NSString的这个方法:
- (NSComparisonResult)compare:(NSString *)string;
其中也有一个NSNumber的同样方法,用法一致。
一般应该怎么使用呢?看下面的例子:
// str1 与 str2 都是字符串
NSComparisonResult cResult = [str1 compare:str2];
switch (cResult) {
case NSOrderedAscending:
{
NSLog(@"str1 大于 str2");
}
break;
case NSOrderedSame:
{
NSLog(@"str1 等于 str2");
}
break;
case NSOrderedDescending:
{
NSLog(@"str1 小于 str2");
}
break;
default:
break;
}
二、排序
排序,往往需要一种规则, 比如大小的比较,排序都是出现在数组中。
一个简单的字符串数组的排序
NSArray* arr = @[@"1", @"3", @"2"];
NSLog(@"原始顺序 \n%@", arr);
{
/** 原始顺序
(
1,
3,
2
)
*/
}
arr = [arr sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
// 这是升序, 如果需要降序, 将 obj1 与 obj2换个位置就可以了
return [obj1 compare:obj2];
}];
NSLog(@"排序后 \n%@", arr);
{
/** 排序后
(
1,
2,
3
)
*/
}
还有一种情况是, 数组中的元素是一个模型, 需要根据其中的一个字段来进行排序. 比如有一个Person集合的数据, 需要根据年龄进行排序.
这个Person类的定义如下:
.h文件
#import <Foundation/Foundation.h>
@interface Person : NSObject
/** 名字 */
@property (nonatomic, copy) NSString* name;
/** 年龄 */
@property (nonatomic, copy) NSString* age;
@end
.m文件
#import "Person.h"
@implementation Person
- (NSString *)description {
return [NSString stringWithFormat:@"name: %@, age: %@", self.name, self.age];
}
@end
例子:
Person* p1 = [[Person alloc] init];
p1.name = @"p1";
p1.age = @"22";
Person* p2 = [[Person alloc] init];
p2.name = @"p2";
p2.age = @"23";
Person* p3 = [[Person alloc] init];
p3.name = @"p3";
p3.age = @"21";
NSArray* persons = @[p1, p2, p3];
NSLog(@"原始顺序 \n%@", persons);
{
/** 原始顺序
(
"name: p1, age: 22",
"name: p2, age: 23",
"name: p3, age: 21"
)
*/
}
persons = [persons sortedArrayUsingComparator:^NSComparisonResult(Person* obj1, Person* obj2) {
// 根据年龄实现升序排序
return [obj1.age compare:obj2.age];
}];
NSLog(@"排序后 \n%@", persons);
{
/** 排序后
(
"name: p3, age: 21",
"name: p1, age: 22",
"name: p2, age: 23"
)
*/
}
三、查找数据
很多时候, 就需要在数组中去查找我们需要的数据, 就拿上面的** Person**来举个例子:
Person* p1 = [[Person alloc] init];
p1.name = @"p1";
p1.age = @"22";
Person* p2 = [[Person alloc] init];
p2.name = @"p2";
p2.age = @"23";
Person* p3 = [[Person alloc] init];
p3.name = @"p3";
p3.age = @"21";
Person* p4 = [[Person alloc] init];
p4.name = @"p1";
p4.age = @"25";
NSArray* persons = @[p1, p2, p3, p4];
// 找出所有 name 是 p1 的人
NSString* name = @"p1";
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"SELF.name CONTAINS[c]%@", name];
NSArray* filtereds = [persons filteredArrayUsingPredicate:predicate];
if (filtereds.count > 0) {
NSLog(@"找到了 \n%@", filtereds);
{
/** 找到了
(
"name: p1, age: 22",
"name: p1, age: 25"
)
*/
}
} else {
NSLog(@"没有找到");
}
这里使用了iOS的** NSPredicate**, 这东西很强大的, 可以参考这篇很全很经典的文章:iOS中的谓词(NSPredicate)使用
四、isEqual:的用法
在一个数组中查找某个数据, 除了使用上面说到的NSPredicate, 还有另一个方法, 但是最好的方式, 还是使用NSPredicate. 那就是重写isEqual:方法.
- (BOOL)isEqual:(Person*)object {
// 如果name相等, 则说明是同一个人
return [self.name isEqual:object.name];
}
看一下实验:
Person* p1 = [[Person alloc] init];
p1.name = @"p1";
p1.age = @"22";
Person* p2 = [[Person alloc] init];
p2.name = @"p2";
p2.age = @"23";
NSArray* persons = @[p1, p2];
Person* p = [[Person alloc] init];
p.name = @"p1";
p.age = @"22";
if ([persons containsObject:p]) {
// 会打印这句话的
NSLog(@"p 在 persons 中");
} else {
NSLog(@"p 不在 persons 中");
}
这种方式其实很low, 知道能这样做就OK.只需要知道containsObject:方法会调用isEqual:即可.
五、unsafe_unretained 与 weak
- 都是弱指针类型
- weak指向的对象销毁了, 当前指针制动变成nil。 则unsafe_unretained不会,所以会导致坏地址访问闪退。
有一个关于NSNotificationCenter的例子:为什么在iOS9之前一定要对observer进行remove, 而之后可以不需要呢? 就是因为在NSNotificationCenter中对observer的引用一个是unsafe_unretained, 一个是weak。
关于这个点,推荐一个很不错的文章:关于__autoreleasing,你真的懂了吗?
六、关于死锁
在主队列中回到主队列, 这样的:
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"dispatch_get_main_queue");
});
运行是这样的:
七、NSTimer注意事项
- 以timer开头的类方法创建的定时器需要手动添加Runloop,通过scheduledTimer开头的则不需要。
- 记得在不用的时候, 以这样的方式关闭定时器:
[_timer invalidate];
_timer = nil;