美文网首页
IOS基础:OC的Foundation语法

IOS基础:OC的Foundation语法

作者: 时光啊混蛋_97boy | 来源:发表于2020-10-19 17:29 被阅读0次

原创:知识点总结性文章
创作不易,请珍惜,之后会持续更新,不断完善
个人比较喜欢做笔记和写总结,毕竟好记性不如烂笔头哈哈,这些文章记录了我的IOS成长历程,希望能与大家一起进步
温馨提示:由于简书不支持目录跳转,大家可通过command + F 输入目录标题后迅速寻找到你所需要的内容

目录

  • 一、公共用法
    • 1、加载及初始化类
    • 2、分配内存空间及初始化对象
    • 3、给对象发送消息(执行方法)
    • 4、复制对象
    • 5、获取Class
    • 6、判断方法
    • 7、重写对象的系统方法
    • 8、SharedApplication
  • 二、头部声明
    • 1、常量和宏
    • 2、枚举
    • 3、属性关键字
  • 三、基本数据类型
    • 1、Null/nil
    • 2、BOOL
    • 3、NSNumber
    • 4、NSData
    • 5、CG类型
    • 6、路径
  • 四、字符串
    • 1、范围
    • 2、格式
    • 3、拷贝
    • 4、替换
    • 5、比较
    • 6、路径
    • 7、字符串转变
    • 8、字符串属性
    • 9、可变字符串
    • 10、富文本
  • 五、集合
    • 1、NSSet
    • 2、NSDictionary
    • 3、NSArray
  • 六、NSDate
    • 1、Date
    • 2、Calendar
  • 七、NSTimer
    • 1、不重复的timer
    • 2、重复的timer
    • 3、Invocation + RunLoop
    • 4、Fire Date + RunLoop
  • 八、NSPredicate
    • 1、谓词语法
    • 2、正则表达式语法
    • 3、包含关系
    • 4、数据过滤
    • 5、占位符
    • 6、正则表达式
    • 7、空值
    • 8、复合谓词
    • 9、Core Data中的使用
  • Demo
  • 参考文献

1、公共用法

1、加载及初始化类

// 运行时加载类或分类调用该方法, 每个类只会调用一次
+ (void)load;

// 类实例化使用前需要先初始化, 一个类调用一次, 如果子类没有实现该方法则会调用父类方法
+ (void)initialize;

load和initialize区别在于:

  • load是只要类所在文件被引用就会被调用,而initialize是在类或者其子类的第一个方法被调用前调用。所以如果类没有被引用进项目,就不会有load调用;但即使类文件被引用进来,但是没有使用,那么initialize也不会被调用。
  • load每个类只会调用一次,initialize也只调用一次,但是如果子类没有实现initialize方法则会调用父类的方法,因此作为父类的initialize方法可能会调用多次。

2、分配内存空间及初始化对象

Student *student = [Student new];
Student *student2 = [[Student alloc] init];
Student *student3 = [[Student allocWithZone:nil] init];

创建新对象时,首先调用alloc为对象分配内存空间,再调用init初始化对象,如[[NSObject alloc] init];而new方法先给新对象分配空间然后初始化对象,因此[NSObject new]等同于[[NSObject alloc] init];关于allocWithZone方法,官方文档解释该方法的参数是被忽略的,正确的做法是传nil或者NULL参数给它。

3、给对象发送消息(执行方法)

直接调用:

// 调用无参无返回值方法
[student running];
// 调用有参无返回值方法
[student readingWithText:@"Hello World!"];
// 调用有参有返回值方法
NSNumber *sum = [student sumWithNum:@(2) num2:@(3)];

我们通常都采用这种直接调用的方式,给对象发消息执行方法。这种方式调用编译时会自动校验方法、参数、返回值是否正确。因此我们必须在头文件中声明方法的使用。

使用performSelector执行:

// 先判断对象是否能调用方法,再执行调用方法
if ([student respondsToSelector:@selector(running)]) {
    // 调用无参无返回值方法
    [student performSelector:@selector(running)];
}

if ([student respondsToSelector:@selector(readingWithText:)]) {
    // 调用有参无返回值方法
    [student performSelector:@selector(readingWithText:) withObject:@"Hello World"];
}
if ([student respondsToSelector:@selector(sumWithNum:num2:)]) {
    // 调用有参有返回值方法
    NSNumber *sum = [student performSelector:@selector(sumWithNum:num2:) withObject:@(2) withObject:@(8)];
}

使用performSelector:是运行时系统负责去找方法,在编译时候不做任何校验;因此在使用时必须先使用respondsToSelector:检查对象是否能调用方法,否则可能出现运行崩溃。performSelector:常用于调用运行时添加的方法,即编译时不存在,但是运行时候存在的方法。另外需要注意的是performSelector:系统提供最多接受两个参数的方法,而且参数和返回都是id类型,并不支持基础数据类型(如:intfloat等)。

使用IMP指针调用:

// 创建SEL
SEL runSel = @selector(running);
SEL readSel = NSSelectorFromString(@"readingWithText:");
SEL sumSel = NSSelectorFromString(@"sumWithNum:num2:");

// 调用无参无返回值方法
IMP rumImp = [student methodForSelector:runSel];
void (*runFunc)(id, SEL) = (void *)rumImp;
runFunc(student, runSel);

// 调用有参无返回值方法
IMP readImp = [[student class] instanceMethodForSelector:readSel];
void (*speakFunc)(id, SEL, NSString *) = (void *)readImp;
speakFunc(student, readSel, @"Hello World");

// 调用有参有返回值方法
IMP sumImp = [student methodForSelector:sumSel];
NSNumber *(*sumFunc)(id, SEL, NSNumber *, NSNumber *) = (void *)sumImp;
NSNumber *sum3 = sumFunc(student, sumSel, @(6), @(6));

SEL 是方法的索引。IMP是函数指针,指向方法的地址。SELIMP是一一对应的关系,因此我们可以通过修改对应关系达到运行时方法交换的目的。

创建SEL对象两种方法:

  • 使用@selector()创建
  • 使用NSSelectorFromString()创建

获取方法IMP指针两种方法:

  • - (IMP)methodForSelector:(SEL)aSelector; 实例方法
  • + (IMP)instanceMethodForSelector:(SEL)aSelector; 类方法

4、复制对象

copy拷贝为不可变对象,mutableCopy拷贝为可变对象。虽然copy对静态对象只是引用计数加1,但是并不影响我们对复制前后的对象进行使用。需要注意的是对于容器对象而言,这两个方法只是复制了容器本身,对容器中包含的对象只是简单的指针引用,并没有深层复制。

// 复制人物
- (instancetype)copyWithZone:(NSZone *)zone
{
    Person *person = [[Person alloc] init];
    person.firstName = self.firstName;
    person.lastName = self.lastName;
    return person;
}

// 使用复制
- (void)useCopy
{
    // 两个源数组
    NSArray *sourceArrayI = [NSArray arrayWithObjects:@"I", @"II", nil];
    NSMutableArray *sourceArrayM = [NSMutableArray arrayWithObjects:@"M", @"MM", nil];
    
    // 两个copy
    NSArray *copyArrayI = [sourceArrayI copy];
    NSArray *copyArrayM = [sourceArrayM copy];
    
    // 两个mutableCopy
    NSMutableArray *mutableArrayI = [sourceArrayI mutableCopy];
    NSMutableArray *mutableArrayM = [sourceArrayM mutableCopy];
    
    // 对象拷贝
    Person *aPerson = [[Person alloc] init];
    Person *copyPerson = [aPerson copy];
    NSLog(@"源对象为:%@",aPerson);
    NSLog(@"copy对象为:%@",copyPerson);
    NSLog(@"copy对象的姓名为:%@", [copyPerson fullName]);
}

输出结果为:

2020-10-20 17:10:50.942504+0800 BasicGrammarDemo[27278:4928170] 源对象为:<Person: 0x600002515320>
2020-10-20 17:10:50.942579+0800 BasicGrammarDemo[27278:4928170] copy对象为:<Person: 0x600002515340>
2020-10-20 17:10:50.942638+0800 BasicGrammarDemo[27278:4928170] copy对象的姓名为:LuoMei Bai

5、获取Class

// 获取类
Class curClass1 = [student class];
Class curClass2 = [ZMStudent class];

// 获取父类
Class supClass1 = [student superclass];
Class supClass2 = [ZMStudent superclass];

6、判断方法

声明两个继承关系的类
@interface Person : NSObject

- (void)run;

@end

@interface Student : Person

@end

@implementation Person

- (void)run
{
    NSLog(@"滚 能换一种说法吗? 蹿吧,孩儿。能文明一点吗?去吧,皮卡丘。能高大上一点吗?奔跑吧,兄弟。能再上档次点吗?世界这么大,你怎么不去看看。能有点诗意吗?你来人间一趟,你要看看太阳。能有点鼓动性吗?奔涌吧,后浪!");
}

@end

@implementation Student

@end
使用判断方法
- (void)useJudgment
{
    // 初始化对象
    Person *person = [Person new];
    Student *studentXie = [Student new];
    Student *studentFan = studentXie;

    // 判断对象是否继承自NSObject
    if ([studentXie isProxy])
    {
        NSLog(@"student对象是继承自NSObject类");
    }

    // 判断两个对象是否相等
    if ([studentXie isEqual:studentFan])
    {
        NSLog(@"studentXie对象与studentFan对象相等,两位同学可能是同一个人");
    }

    // 判断对象是否是指定类
    if ([person isKindOfClass:[Person class]])
    {
        NSLog(@"person对象是Person类,即人是人类");
    }

    // 判断对象是否是指定类或子类
    if ([studentXie isKindOfClass:[Person class]])
    {
        NSLog(@"studentXie对象是Person类的子类,谢同学再颓废没有生气也是个活生生的人呀");
    }

    // 判断某个类是否是另一个类的子类
    if ([Student isSubclassOfClass:[Person class]])
    {
        NSLog(@"Student类是Person类的子类");
    }

    // 判判断对象是否遵从协议
    if ([studentXie conformsToProtocol:@protocol(NSObject)])
    {
        NSLog(@"studentXie对象遵循NSObject协议");
    }

    // 判断类是否遵从给定的协议
    if ([Student conformsToProtocol:@protocol(NSObject)])
    {
        NSLog(@"Student类遵循NSObject协议");
    }

    // 判断对象是否能够调用给定的方法
    if ([studentXie respondsToSelector:@selector(run)])
    {
        NSLog(@"student对象可以调用run方法");
    }

    // 判断实例是否能够调用给定的方法
    if ([Student instancesRespondToSelector:@selector(run)])
    {
        NSLog(@"Student类可以调用run方法");
    }
}
输出结果
2020-10-20 16:46:46.061658+0800 BasicGrammarDemo[26898:4909800] studentXie对象与studentFan对象相等,两位同学可能是同一个人
2020-10-20 16:46:46.061769+0800 BasicGrammarDemo[26898:4909800] person对象是Person类,即人是人类
2020-10-20 16:46:46.061831+0800 BasicGrammarDemo[26898:4909800] studentXie对象是Person类的子类,谢同学再颓废没有生气也是个活生生的人呀
2020-10-20 16:46:46.061902+0800 BasicGrammarDemo[26898:4909800] Student类是Person类的子类
2020-10-20 16:46:46.061988+0800 BasicGrammarDemo[26898:4909800] studentXie对象遵循NSObject协议
2020-10-20 16:46:46.062055+0800 BasicGrammarDemo[26898:4909800] Student类遵循NSObject协议
2020-10-20 16:46:46.062127+0800 BasicGrammarDemo[26898:4909800] student对象可以调用run方法
2020-10-20 16:46:46.062196+0800 BasicGrammarDemo[26898:4909800] Student类可以调用run方法

7、重写对象的系统方法

a、重写系统方法
@interface Animal : NSObject <NSCopying>

@property(nonatomic, copy) NSString *name;
@property(nonatomic, assign) NSString *age;

@end

@implementation Animal

// 重写isEqual:
- (BOOL)isEqual:(id)object
{
    // 自身
    if (self == object)
    {
        return YES;
    }
    
    // 类型相同
    if ([object class] == [Animal class])
    {
        // 转化
        Animal *target = (Animal *)object;
        
        // 设置判断标准
        BOOL result = ([self.name isEqualToString:target.name] && (self.age == target.age));
        return result;
    }
    return NO;
}

// 重写hash
- (NSUInteger)hash
{
    
    NSUInteger nameHash = (self.name == nil ? 0 : [self.name hash]);
    NSUInteger ageHash = (self.age == nil ? 0 : [self.name hash]);
    
    return nameHash * 31 + ageHash;
}

// 重写description
- (NSString *)description
{
    return [NSString stringWithFormat:@"name:%@,age:%@", self.name,self.age];
}

// 重写copyWithZone
- (id)copyWithZone:(NSZone *)zone
{
    Animal *new = [[[self class] allocWithZone:zone] init];
    new.name = self.name;
    new.age = self.age;
    return new;
}

@end
b、调用方式
- (void)useCover
{
    Animal *animal = [[Animal alloc] init];
    animal.name = @"xiejiapei";
    animal.age = @"23";
    NSLog(@"重写了description后,源对象为:%@",[animal description]);
    NSLog(@"源对象hash为:%lu",(unsigned long)[animal hash]);
    
    Animal *copyAnimal = [animal copy];
    NSLog(@"copy对象为:%@",copyAnimal);
    
    if ([copyAnimal isEqual:animal])
    {
        NSLog(@"两个对象相等");
    }
}
c、输出结果
2020-11-03 10:05:35.037203+0800 FoundationDemo[93106:3989340] 重写了description后,源对象为:name:xiejiapei,age:23
2020-11-03 10:05:35.037308+0800 FoundationDemo[93106:3989340] 源对象hash为:3770145254414366752
2020-11-03 10:05:35.037378+0800 FoundationDemo[93106:3989340] copy对象为:name:xiejiapei,age:23
2020-11-03 10:05:35.037432+0800 FoundationDemo[93106:3989340] 两个对象相等

8、SharedApplication

- (void)useSharedApplication
{
    // 获得UIApplicationDelegate对象
    [[UIApplication sharedApplication] delegate];
    
    // 获得UIWindow对象
    [[UIApplication sharedApplication] keyWindow];
    
    // 打开设置界面
    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
    
    // 远程的控制相关
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    
    // 不让手机休眠
    [UIApplication sharedApplication].idleTimerDisabled = YES;
   
    // 后台剩余时间
    NSTimeInterval remainTime = [[UIApplication sharedApplication] backgroundTimeRemaining];
    NSLog(@"剩余时间 = %f",remainTime);
    
    // 后台刷新的状态
    [[UIApplication sharedApplication] backgroundRefreshStatus];
    
    // 开启/关闭任务
    [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"task" expirationHandler:^{
    }];
    [[UIApplication sharedApplication] endBackgroundTask:1];
}

二、头部声明

1、常量和宏

  • 宏在预编译时处理(宏在编译开始之前就会被替换),而const会在编译时被处理
  • #define宏没有类型,宏不做任何类型检查,不会报编译错误,只是替换,而const常量有具体的类型,会编译检查,会报编译错误
  • 宏能定义一些函数,方法,而const不能
  • 使用大量宏,容易造成编译时间久,因为每次都需要重新替换
  • 宏定义时不分配内存,变量定义时分配内存
  • 预编译期间进行宏替换,分配内存,再进行宏替换,又一次分配内存,内存中有若干个拷贝。const doulbe Pi —— double i=Pi; 此时为Pi分配内存,以后不再分配!只有一份拷贝(因为是全局的只读变量,存在静态区)
// const常量:后跟谁定谁
const NSString *constString = @"谢佳培";
NSString *const stringConst = @"甜的";

 // 等价于char *s1;  char s2
#define MyString char *s1,s2

// 常用宏定义的颜色、字体字号
#define ROW_SIZE 20
#define Blue  [UIColor colorWithRed:(0x##r)/255.0 green:(0x##g)/255.0 blue:(0x##b)/255.0 alpha:1]

// 宏定义获取rootViewController
#define RootVC [UIApplication sharedApplication].delegate.window.rootViewController

// 宏定义获取当前的界面
#define TopVC ([RootVC isKindOfClass:[UITabBarController class]]?[((UITabBarController *)RootVC).selectedViewController topViewController]:RootVC)

2、枚举

  • define写在方法/函数中则作用域从写的地方开始有效,直至使用#undef(不写此指令则后面一直有效),typedef写在方法/函数中则作用域,只在此方法/函数中有效。
  • typedef是类型替换,直接参与编译,而define只是简单的文本替换。
C语言格式
// 给NSTimeInterval取别名为MyTime
typedef NSTimeInterval MyTime;

// c语言格式,给Person结构体取别名为MyPerson
// 使用:MyPerson p = {"jack"};
typedef struct Person {
    char *name;
} MyPerson;

// c语言格式,给Gender枚举取别名为MyGender
// 使用:MyGender g = Man;
typedef enum Gender {
    Man,
    Woman
} MyGender;
OC语言格式
typedef NS_ENUM(NSInteger, NumberType)
{
     NumberTypeInt = 0,
     NumberTypeFloat = 1,
     NumberTypeDouble = 2
};
NumberType type = NumberTypeInt;

typedef NS_OPTIONS(NSUInteger, TMEnumTest)
{
    TMEnumTestOne     = 0,          // 0
    TMEnumTestTwo     = 1 << 0,     // 1
    TMEnumTestThree   = 1 << 1,     // 2
    TMEnumTestFour    = 1 << 2,     // 4
};
TMEnumTest test = TMEnumTestTwo | TMEnumTestThree; 


typedef NS_OPTIONS(NSUInteger, LifeRoleOptions)
{
    LifeRoleOptionsFather =   1UL << 0,
    LifeRoleOptionsSon = 1UL << 1,
    LifeRoleOptionsHusband = 1UL << 3,
};
LifeRoleOptions lifeRole = LifeRoleOptionsFather | LifeRoleOptionsSon;

// 给block取别名MyBlock
typedef void(^MyBlock) (int a,int b);
使用方式
- (void)useTypedef
{
    // 添加TMEnumTestFour到test中
    test += TMEnumTestFour;
    // 将TMEnumTestThree从test中去除
    test -= TMEnumTestThree;
    // 判断 TMEnumTestFour枚举 是否被包含
    if (test & TMEnumTestFour)
    {
        NSLog(@"数字是:四");
    }
    // 判断 TMEnumTestThree枚举 是否被包含
    if (test & TMEnumTestThree)
    {
        NSLog(@"数字是:三");
    }
    
    if (lifeRole & LifeRoleOptionsFather)
    {
        NSLog(@"人生角色:父亲");
    }
    
    if (lifeRole & LifeRoleOptionsHusband)
    {
        NSLog(@"人生角色:丈夫");
    }
}
输出结果
2020-10-20 15:24:20.763915+0800 BasicGrammarDemo[25511:4841344] 数字是:四
2020-10-20 15:24:20.764021+0800 BasicGrammarDemo[25511:4841344] 人生角色:父亲

3、属性关键字

类型
  • atomic:系统默认,声明的属性保证赋值和获取是线程安全的,不保证添加和移除是线程安全的(如数组)
  • noatomic:经常声明
  • retain/strong
  • assign/unsafe_unretained:修饰基本数据类型,如intBool。修饰对象类型时候,不改变其引用计数。对象释放后,会产生悬垂指针,仍访问会产生内存泄露。
  • weak:不改变修饰对象的引用计数,对象释放后,自动置为nil
  • copy浅拷贝和深拷贝的区别:是否开辟了新的内存空间,是否影响了引用计数。可变对象copy 后是NSArray 不可以调用add delete等方法。只有不可变对象的copy是浅拷贝,其他都是深拷贝。
属性声明
//默认关键字
@property (atomic, strong, readwrite) NSString *firstName;

@property (readonly, getter=isShit) BOOL shit;

@property (nonatomic, strong) NSArray *vcTitles;
@property (nonatomic, strong) NSArray<NSArray *> *pickerData;


@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) personBlock runFinishBlock;

@property (nonatomic, weak) id<WorkProtocol> delegate;
@property (nonatomic, weak) id<CountToolDataSource> dataSource;

@property (nonatomic, assign) int age;
@property (nonatomic, assign) BOOL bodyTextChanged;
@property (nonatomic, assign) NSTimeInterval created;
使用演示
@interface PersonClass : NSObject

@property (nonatomic, strong) NSObject *objStrong;
@property (nonatomic, weak) NSObject *objWeak;
@property (nonatomic, assign) NSObject *objAssign;
@property (nonatomic, copy) NSString *objCopy;

@end

// 使用属性关键字
- (void)useAttributeKey
{
    PersonClass *aPerson = [[PersonClass alloc] init];
    aPerson.objStrong = [[NSObject alloc] init];
    
    // 系统会警告,但不会报错
    aPerson.objWeak = [[NSObject alloc] init];
    aPerson.objAssign = [[NSObject alloc] init];
    
    NSMutableString *testStr = [[NSMutableString alloc] initWithString:@"我知道什么呢?"];
    aPerson.objCopy = testStr;
    [aPerson setObjCopy:testStr];
    [testStr appendString:@"什么都知道"];
    
    // 正确的方式
    NSLog(@"objWeak %@", aPerson.objStrong);
    
    // weak会释放为null
    NSLog(@"objWeak %@", aPerson.objWeak);
    
    // Assign会崩溃
    // NSLog(@"objAssign %@", aPerson.objAssign);
    
    // Copy后,原字符串改变对新字符串无影响
    NSLog(@"testStr %@", testStr);
    NSLog(@"objCopy %@", aPerson.objCopy);
}
输出结果
2020-10-20 15:38:17.996696+0800 BasicGrammarDemo[25777:4854926] objWeak <NSObject: 0x60000006c1b0>
2020-10-20 15:38:17.996794+0800 BasicGrammarDemo[25777:4854926] objWeak (null)
2020-10-20 15:38:17.996872+0800 BasicGrammarDemo[25777:4854926] testStr 我知道什么呢?什么都知道
2020-10-20 15:38:17.996936+0800 BasicGrammarDemo[25777:4854926] objCopy 我知道什么呢?

三、基本数据类型

1、Null/nil

// 默认值: NO/0/nil
Person *aPerson = nil;
aPerson.age // 0

// 用在不能在数组和词典对象中放入nil ,又确实需要一个特殊的对象来表示空值
+ (NSNull *) null 

2、BOOL

BOOL hidden = YES;
BOOL bigger = 0 > 1;

if (-1)
{
    NSLog(@"not 0 = YES");
}

NSObject *boolObj = [[NSObject alloc] init];
if (boolObj)
{
    NSLog(@"not nil = YES");
}

输出结果为:

2020-10-21 11:40:25.715805+0800 BasicGrammarDemo[31446:5105441] not 0 = YES
2020-10-21 11:40:25.715873+0800 BasicGrammarDemo[31446:5105441] not nil = YES

3、NSNumber

// 用语法糖进行声明,可转换为多种数据类型
NSNumber *intNumber = @(-1);
NSNumber *boolNumber = @(YES);
NSNumber *charNumber = @('A');
NSLog(@"int(-1)值:%@,bool(YES)值:%@ ,char(A)值:%@", intNumber, boolNumber, charNumber);
NSLog(@"字面A的charValue值:%d,stringValue值:%@,intValue值:%d", charNumber.charValue, charNumber.stringValue, charNumber.intValue);

输出结果为:

2020-10-21 11:44:24.847241+0800 BasicGrammarDemo[31501:5108050] int(-1)值:-1,bool(YES)值:1 ,char(A)值:65
2020-10-21 11:44:24.847298+0800 BasicGrammarDemo[31501:5108050] 字面A的charValue值:65,stringValue值:65,intValue值:65

4、NSData

NSString *dataString = @"XieJiaPei";
NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
NSLog(@"string(XieJiaPei) 转化为 data:%@", data);

NSData *zeroData = [NSData data];
NSLog(@"空数据为:%@", zeroData);

NSMutableData *appendData = [zeroData mutableCopy];
[appendData appendData:data];
NSLog(@"在空数据后追加数据后结果为:%@", appendData);

输出结果为:

2020-10-21 13:44:31.226384+0800 BasicGrammarDemo[32605:5160936] string(XieJiaPei) 转化为 data:{length = 9, bytes = 0x5869654a6961506569}
2020-10-21 13:44:31.226465+0800 BasicGrammarDemo[32605:5160936] 空数据为:{length = 0, bytes = 0x}
2020-10-21 13:44:31.226546+0800 BasicGrammarDemo[32605:5160936] 在空数据后追加数据后结果为:{length = 9, bytes = 0x5869654a6961506569}

5、CG类型

- (void)useCG
{
    // 状态栏高度
    CGFloat statusBarHeight = [UIApplication sharedApplication].statusBarFrame.size.height;
    NSLog(@"状态栏高度:%f",statusBarHeight);
    
    // 如何把一个CGPoint存入数组里
    CGPoint point = CGPointMake(0, 0);
    NSMutableArray *array = [[NSMutableArray alloc] initWithObjects:NSStringFromCGPoint(point), nil];
    point = CGPointFromString(array[0]);
    NSLog(@"如何把一个CGPoint存入数组里: %@",array);
}

输出结果为:

2020-10-30 13:40:44.198593+0800 FoundationDemo[42880:1608020] 状态栏高度:44.000000
2020-10-30 13:40:44.198740+0800 FoundationDemo[42880:1608020] 如何把一个CGPoint存入数组里: (
    "{0, 0}"
)

四、字符串

1、范围

a、NSMakeRange
NSRange range = NSMakeRange(2, 4);
NSString *fullString = @"abcdefghijk";
NSString *subString = [fullString substringWithRange:range];
NSLog(@"原字符串为abcdefghijk,其(2,4)范围内的子字符串为:%@", subString);

输出结果为:

2020-10-21 13:52:18.515144+0800 BasicGrammarDemo[32785:5169598] 原字符串为abcdefghijk,其(2,4)范围内的子字符串为:cdef
b、substringToIndex
NSString *intString = @"456789";
NSString *charString = @"abcdef";
NSString *chineseString = @"中文哈哈哈哈";

NSString *subIntString = [intString substringToIndex:2];
NSString *subCharString = [charString substringToIndex:2];
NSString *subChineseString = [chineseString substringToIndex:2];

NSLog(@"substringToIndex:2,456789的子串为:%@,abcdef的子串为:%@,中文哈哈哈哈的子串为:%@", subIntString,subCharString,subChineseString);

输出结果为:

2020-10-21 13:57:36.238543+0800 BasicGrammarDemo[32871:5174143] substringToIndex:2,456789的子串为:45,abcdef的子串为:ab,中文哈哈哈哈的子串为:中文
c、substringFromIndex
NSString *subFromString = [chineseString substringFromIndex:2];
NSLog(@"原字符串为中文哈哈哈哈,FromIndex:2范围内的子字符串为:%@", subFromString);

输出结果为:

2020-10-21 14:14:07.313580+0800 BasicGrammarDemo[33183:5188958] 原字符串为中文哈哈哈哈,FromIndex:2范围内的子字符串为:哈哈哈哈

2、格式

a、stringWithFormat
NSString *stringWithFormat = [NSString stringWithFormat:@"字符串为: %@, 两位小数的浮点数为: %1.2f",@"XieJiaPei", 31415.9265];
NSLog(@"带格式的字符串 = %@", stringWithFormat);

输出结果为:

2020-10-21 14:04:51.764665+0800 BasicGrammarDemo[33017:5180791] 带格式的字符串 = 字符串为: XieJiaPei, 两位小数的浮点数为: 31415.93
b、stringByAppendingFormat
NSNumber *number = @12345;
NSDictionary *dictionary = @{@"date": [NSDate date]};
NSString *baseString = @"Test: ";
NSString *stringByAppendingFormat = [baseString stringByAppendingFormat:@"数字: %@, 字典: %@", number, dictionary];
NSLog(@"追加格式字符串 = %@", stringByAppendingFormat);

输出结果为:

2020-10-21 14:09:38.901710+0800 BasicGrammarDemo[33102:5185253] 追加格式字符串 = Test: 数字: 12345, 字典: {
    date = "2020-10-21 06:09:38 +0000";
}

3、拷贝

NSString *copyIntString = [intString copy];
NSString *copyCharString = [charString copy];
NSString *copyChineseString = [chineseString copy];

NSLog(@"复制后的字符串,%@,%@,%@", copyIntString,copyCharString,copyChineseString);

输出结果为:

2020-10-21 14:01:51.381827+0800 BasicGrammarDemo[32960:5177962] 复制后的字符串,456789,abcdef,中文哈哈哈哈

4、替换

NSString *replaceChineseString = [chineseString stringByReplacingOccurrencesOfString:@"哈" withString:@"好"];
NSLog(@"原字符串为中文哈哈哈哈,替换后为:%@", replaceChineseString);

NSString *pureChineseString = [chineseString stringByReplacingOccurrencesOfString:@"哈" withString:@""];
NSLog(@"原字符串为中文哈哈哈哈,用替换的方式进行删除后为:%@", pureChineseString);

输出结果为:

2020-10-21 14:18:03.822172+0800 BasicGrammarDemo[33238:5192253] 原字符串为中文哈哈哈哈,替换后为:中文好好好好
2020-10-21 14:18:03.822240+0800 BasicGrammarDemo[33238:5192253] 原字符串为中文哈哈哈哈,用替换的方式进行删除后为:中文

5、比较

NSString *abc = @"abc";
NSString *aBc = @"aBc";
NSString *aB = @"aB";
NSComparisonResult abcOrder = [abc compare:aBc];
NSComparisonResult aBOrder = [aB compare:aBc];
NSLog(@"abc compare:aBc的结果为:%ld,即abc > aBc",(long)abcOrder);
NSLog(@"aB compare:aBc的结果为:%ld,即aB < aBc",(long)aBOrder);

输出结果为:

2020-10-21 14:22:18.913094+0800 BasicGrammarDemo[33347:5197161] abc compare:aBc的结果为:1,即abc > aBc
2020-10-21 14:22:18.913165+0800 BasicGrammarDemo[33347:5197161] aB compare:aBc的结果为:-1,即aB < aBc

6、路径

a、hasPrefix/hasSuffix
if ([aBc hasSuffix:@"Bc"])
{
    NSLog(@"aBc的后缀为Bc");
}

if ([aBc hasPrefix:@"aB"])
{
    NSLog(@"aBc的前缀为aB");
}

输出结果为:

2020-10-21 14:25:09.571763+0800 BasicGrammarDemo[33434:5201268] aBc的后缀为Bc
2020-10-21 14:25:09.571853+0800 BasicGrammarDemo[33434:5201268] aBc的前缀为aB
b、stringByAppendingPathComponent
NSString *homePath = NSHomeDirectory();// 能够访回当前用户的主目录
NSString *workPath = [homePath stringByAppendingPathComponent:@"LuckCoffee"];
NSLog(@"瑞幸咖啡的存储路径为:%@", workPath);

输出结果为:

2020-10-21 14:28:37.083043+0800 BasicGrammarDemo[33522:5205708] 瑞幸咖啡的存储路径为:/Users/xiejiapei/Library/Developer/CoreSimulator/Devices/8D07F1D9-24C5-45A2-8AA2-3AB9EF752D6F/data/Containers/Data/Application/202BCFAD-50E8-499B-833C-93426D5EAB1E/LuckCoffee
c、lastPathComponent/pathExtension
NSString *filePath = @"/tmp/image/cat.tiff";
NSLog(@"路径为:/tmp/image/cat.tiff,最后一个部分为:%@,文件的扩展名为:%@",[filePath lastPathComponent],[filePath pathExtension]);

输出结果为:

2020-10-21 15:14:28.535638+0800 BasicGrammarDemo[34137:5237242] 路径为:/tmp/image/cat.tiff,最后一个部分为:cat.tiff,文件的扩展名为:tiff

7、字符串转变

a、componentsSeparatedByString / componentsJoinedByString
// 分割
NSArray *pathArray = [homePath componentsSeparatedByString:@"/"];
NSLog(@"NSHomeDirectory的路径为:%@", homePath);
NSLog(@"路径转变为数组后为:%@", pathArray);

// 拼接
NSString *joinPath = [pathArray componentsJoinedByString:@"/"];
NSLog(@"将数组拼接成为路径:%@",joinPath);

输出结果为:

2020-10-21 15:25:32.289578+0800 BasicGrammarDemo[34365:5248464] NSHomeDirectory的路径为:/Users/xiejiapei/Library/Developer/CoreSimulator/Devices/8D07F1D9-24C5-45A2-8AA2-3AB9EF752D6F/data/Containers/Data/Application/E1A549FF-396C-402B-934A-35BB04F60A1A
2020-10-21 15:25:32.289679+0800 BasicGrammarDemo[34365:5248464] 路径转变为数组后为:(
    "",
    Users,
    xiejiapei,
    Library,
    Developer,
    CoreSimulator,
    Devices,
    "8D07F1D9-24C5-45A2-8AA2-3AB9EF752D6F",
    data,
    Containers,
    Data,
    Application,
    "E1A549FF-396C-402B-934A-35BB04F60A1A"
)
2020-10-21 15:25:32.289762+0800 BasicGrammarDemo[34365:5248464] 将数组拼接成为路径:/Users/xiejiapei/Library/Developer/CoreSimulator/Devices/8D07F1D9-24C5-45A2-8AA2-3AB9EF752D6F/data/Containers/Data/Application/E1A549FF-396C-402B-934A-35BB04F60A1A
b、initWithData
NSString *name = @"XieJiaPei";

// 将NSString转化为NSData
NSData *data = [name dataUsingEncoding:NSUTF8StringEncoding];

// 用存储在data中的二进制数据来初始化NSString对象
NSString *dataName = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"用存储在data中的二进制数据来初始化NSString对象,结果为:%@",dataName);

输出结果为:

2020-10-21 15:14:28.536003+0800 BasicGrammarDemo[34137:5237242] 用存储在data中的二进制数据来初始化NSString对象,结果为:XieJiaPei
c、把NSArray集合转换为格式字符串
NSArray *array = @[@"xie",@"jia",@"pei",@"fan",@"yi",@"cheng",@"lin",@"feng",@"mian"];
NSMutableString *result = [NSMutableString stringWithString:@"["];
for (id object in array)
{
    [result appendString:[object description]];
    [result appendString:@","];
}
// 去掉字符串最后的两个字符
[result deleteCharactersInRange:NSMakeRange(result.length - 2, 2)];
[result appendString:@"]"];
NSLog(@"把NSArray集合转换为字符串:%@",result);

输出结果为:

2020-10-30 16:49:02.894530+0800 FoundationDemo[46760:1747913] 把NSArray集合转换为字符串:[xie,jia,pei,fan,yi,cheng,lin,feng,mia]

8、字符串属性

// 字符串对象内部使用Unicode 编码,返回C语言字符串的指针
NSLog(@"Unicode 编码:%s",[name UTF8String]);

// 小写与大写
NSLog(@"原字符串为:XieJiaPei,小写结果为:%@",[name lowercaseString]);
NSLog(@"原字符串为:XieJiaPei,大写结果为::%@",[name uppercaseString]);
NSLog(@"原字符串为:XieJiaPei,首字母变为大写结果为::%@",[name capitalizedString]);

// 分别被用来把NSString类型的字符串转为float、int、NSinteger和BOOL类型的数值
NSLog(@"原字符串为:414.5678,floatValue值为:%f",[@"414.5678" floatValue]);
NSLog(@"原字符串为:512,intValue值为:%d",[@"512" intValue]);
NSLog(@"原字符串为:1024,integerValue值为:%ld",(long)[@"1024" integerValue]);
NSLog(@"原字符串为:OK,boolValue值为:%ld",(long)[@"2" boolValue]);

输出结果为:

2020-10-21 15:16:56.468275+0800 BasicGrammarDemo[34195:5239924] Unicode 编码:XieJiaPei
2020-10-21 15:16:56.468392+0800 BasicGrammarDemo[34195:5239924] 原字符串为:XieJiaPei,小写结果为:xiejiapei
2020-10-21 15:16:56.468487+0800 BasicGrammarDemo[34195:5239924] 原字符串为:XieJiaPei,大写结果为::XIEJIAPEI
2020-10-21 15:16:56.468600+0800 BasicGrammarDemo[34195:5239924] 原字符串为:XieJiaPei,首字母变为大写结果为::Xiejiapei
2020-10-21 15:16:56.468715+0800 BasicGrammarDemo[34195:5239924] 原字符串为:414.5678,floatValue值为:414.567810
2020-10-21 15:16:56.468827+0800 BasicGrammarDemo[34195:5239924] 原字符串为:512,intValue值为:512
2020-10-21 15:16:56.468971+0800 BasicGrammarDemo[34195:5239924] 原字符串为:1024,integerValue值为:1024
2020-10-21 15:16:56.469081+0800 BasicGrammarDemo[34195:5239924] 原字符串为:OK,boolValue值为:1

9、可变字符串

// 随着字符串的变化而自动扩展内存,所以capacity不需要非常精密
NSMutableString* mutableString = [[NSMutableString alloc] initWithCapacity:20];

// 在原来的字符串尾部添加,返回void,不产生新字符串
[mutableString appendString:@"所谓平庸"];

// 在原来的字符串尾部添加格式化字符串
[mutableString appendFormat:@"是在于认清%i个人的限度,而安于这个限度。",1];

// 插入字符串
[mutableString insertString:@"," atIndex:4];

// 替换
[mutableString replaceCharactersInRange:NSMakeRange(2, 2) withString:@"幸福"];

NSLog(@"可变字符串为:%@",mutableString);

输出结果为:

2020-10-21 15:29:30.122108+0800 BasicGrammarDemo[34466:5253526] 可变字符串为:所谓幸福,是在于认清1个人的限度,而安于这个限度。

10、富文本

下划线
NSString *singleLineText = @"Single Line";

// 下划线
NSAttributedString *singleLineTextAttr = [[NSAttributedString alloc] initWithString:singleLineText attributes:@{NSUnderlineStyleAttributeName: @(1)}];

UILabel *singleLineLabel = [[UILabel alloc] initWithFrame:CGRectMake(150, 100, 100, 50)];
singleLineLabel.attributedText = singleLineTextAttr;
[self.view addSubview:singleLineLabel];

五、集合

1、NSSet

a、集合
- (void)set
{
    NSSet *set = [NSSet setWithObjects:@"xie",@"jia",@"pei", nil];
    NSSet *newSet = [NSSet setWithSet:set];
    NSSet *differenceSet = [NSSet setWithObjects:@"xie",@"liu",@"ying", nil];
    NSSet *deepCopySet = [[NSSet alloc] initWithSet:set copyItems:YES];
    NSLog(@"如果是深拷贝,所有元素必须符合NSCoping协议,拷贝后集合为:%@",deepCopySet);
    
    NSLog(@"集合中元素个数:%lu",(unsigned long)[set count]);
    
    set = [set setByAddingObject:@"love"];
    NSLog(@"将添加单个元素后生成的新集合赋给set:%@",set);
    
    set = [set setByAddingObjectsFromSet:newSet];
    NSLog(@"添加多个元素,相当于并集:%@",set);
    
    [set intersectsSet:differenceSet];
    NSLog(@"是否有交集:%@",set);
    
    [set isSubsetOfSet:differenceSet];
    NSLog(@"是否有子集:%@",set);
    
    [set containsObject:@"xie"];
    NSLog(@"集合中是否包含元素:%@",set);
    
    [set anyObject];
    NSLog(@"随取元素:%@",set);
    
    NSSet *filteredSet = [set objectsPassingTest:^BOOL(id  _Nonnull obj, BOOL * _Nonnull stop){
        return ([obj isEqualToString:@"xie"]);
    }];
    NSLog(@"过滤集合:%@",filteredSet);
}

输出结果为:

2020-11-03 09:30:14.902811+0800 FoundationDemo[92415:3957705] 如果是深拷贝,所有元素必须符合NSCoping协议,拷贝后集合为:{(
    xie,
    jia,
    pei
)}
2020-11-03 09:30:14.902907+0800 FoundationDemo[92415:3957705] 集合中元素个数:3
2020-11-03 09:30:14.902984+0800 FoundationDemo[92415:3957705] 将添加单个元素后生成的新集合赋给set:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903052+0800 FoundationDemo[92415:3957705] 添加多个元素,相当于并集:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903110+0800 FoundationDemo[92415:3957705] 是否有交集:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903186+0800 FoundationDemo[92415:3957705] 是否有子集:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903257+0800 FoundationDemo[92415:3957705] 集合中是否包含元素:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903325+0800 FoundationDemo[92415:3957705] 随取元素:{(
    jia,
    xie,
    pei,
    love
)}
2020-11-03 09:30:14.903401+0800 FoundationDemo[92415:3957705] 过滤集合:{(
    xie
)}
b、可变集合
- (void)mutableSet
{
    // 添加
    NSArray *array = @[@"xie",@"jia",@"pei"];
    NSMutableSet *set = [NSMutableSet setWithCapacity:10];
    [set addObjectsFromArray:array];
    NSSet *newSet = [NSSet setWithSet:set];
    
    // 删除
    [set removeObject:@"xie"];
    NSLog(@"删除元素后,新set为:%@",set);
    
    // 并集
    [set unionSet:newSet];
    NSLog(@"set取并集为:%@",set);
    
    // 交集
    [set intersectsSet:newSet];
    NSLog(@"set取交集为:%@",set);
    
    // 差集
    [set minusSet:newSet];
    NSLog(@"set取差集为:%@",set);
}

输出结果为:

2020-11-03 09:37:00.269452+0800 FoundationDemo[92558:3964819] 删除元素后,新set为:{(
    jia,
    pei
)}
2020-11-03 09:37:00.269550+0800 FoundationDemo[92558:3964819] set取并集为:{(
    xie,
    jia,
    pei
)}
2020-11-03 09:37:00.269630+0800 FoundationDemo[92558:3964819] set取交集为:{(
    xie,
    jia,
    pei
)}
2020-11-03 09:37:00.269690+0800 FoundationDemo[92558:3964819] set取差集为:{(
)}
c、带重复次数的集合
- (void)countedSet
{
    NSCountedSet *set = [NSCountedSet setWithObjects:@"xie",@"jia", nil];
    [set addObject:@"xie"];
    [set addObject:@"pei"];
    NSLog(@"带有重复次数的set为:%@",set);
    NSLog(@"xie这个字符串出现的次数为:%lu",(unsigned long)[set countForObject:@"xie"]);
}

输出结果为:

2020-11-03 09:40:29.104474+0800 FoundationDemo[92640:3968983] 带有重复次数的set为:<NSCountedSet: 0x6000009692c0> (xie [2], jia [1], pei [1])
2020-11-03 09:40:29.104555+0800 FoundationDemo[92640:3968983] xie这个字符串出现的次数为:2

2、NSDictionary

a、创建字典并取值
- (void)createDictionary
{
    PersonClass *person = [[PersonClass alloc] init];
    
    // 通过语法糖创建字典
    NSDictionary *dict = @{@"name": @"XieJiaPei", @"age": @22, @4: @5, person: @"FanYiCheng"};
    NSLog(@"原始字典为:%@",dict);
    
    // 从字典中取值
    NSLog(@"字典中的姓名为:%@,年龄为:%@,倘若没有Key值为:%@",dict[@"name"],[dict objectForKey:@"age"],dict[@"noKey"]);
    
    // 通过初始化方法创建字典
    NSDictionary *dictionary = [[NSDictionary alloc] initWithObjectsAndKeys: @"XieJiaPei",@"name",@22,@"age",person,@"FanYiCheng",nil];
    NSLog(@"key-value对数量: %lu",(unsigned long)[dictionary count]);
    NSLog(@"allKey: %@",[dictionary allKeys]);
    NSLog(@"allValues: %@",[dictionary allValues]);
    NSLog(@"key不同,值相同,这种情况的所有key为: %@",[dictionary allKeysForObject:@"XieJiaPei"]);
}

输出结果为:

2020-10-30 17:34:07.613893+0800 FoundationDemo[47518:1783828] 原始字典为:{
    age = 22;
    "<PersonClass: 0x600002828300>" = (null);
    name = XieJiaPei;
    4 = 5;
}
2020-10-30 17:34:07.613982+0800 FoundationDemo[47518:1783828] 字典中的姓名为:XieJiaPei,年龄为:22,倘若没有Key值为:(null)
2020-10-30 17:34:07.614057+0800 FoundationDemo[47518:1783828] key-value对数量: 3
2020-10-30 17:34:07.614140+0800 FoundationDemo[47518:1783828] allKey: (
    name,
    age,
    FanYiCheng
)
2020-10-30 17:34:07.614212+0800 FoundationDemo[47518:1783828] allValues: (
    XieJiaPei,
    22,
    "<PersonClass: 0x600002828980>"
)
2020-10-30 17:34:07.614295+0800 FoundationDemo[47518:1783828] key不同,值相同,这种情况的所有key为: (
    name
)
b、遍历字典
- (void)enumerateDictionary
{
    PersonClass *person = [[PersonClass alloc] init];
    NSDictionary *dict = @{@"name": @"XieJiaPei", @"age": @22, @4: @5, person: @"FanYiCheng"};
    
    // 使用指定代码块来迭代执行该集合中所有key-value对
    [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop)
    {
        NSLog(@"key的值为:%@,value的值:%@", key, obj);
    }];
}

输出结果为:

2020-10-30 17:40:27.704477+0800 FoundationDemo[47616:1788769] key的值为:age,value的值:22
2020-10-30 17:40:27.704543+0800 FoundationDemo[47616:1788769] key的值为:<PersonClass: 0x600001435f80>,value的值:FanYiCheng
2020-10-30 17:40:27.704610+0800 FoundationDemo[47616:1788769] key的值为:name,value的值:XieJiaPei
2020-10-30 17:40:27.704690+0800 FoundationDemo[47616:1788769] key的值为:4,value的值:5
c、写入文件
- (void)dictionaryWriteToFile
{
    // 我发现要写入plist文件,key必须为string类型
    NSDictionary *dict = @{@"name": @"XieJiaPei", @"age": @22, @"4": @5};
    
    NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *filePath = [documentPath stringByAppendingPathComponent:@"jia.plist"];
    
    // 将路径转换为本地url形式
    NSURL *fileUrl = [NSURL fileURLWithPath:filePath];

    // writeToURL 的好处是,既可以写入本地url也可以写入远程url,苹果推荐使用此方法写入plist文件
    if ( [dict writeToURL:fileUrl atomically:YES] )
    {
        NSLog(@"成功写入文件,路径为:%@",filePath);
    }
    
    NSDictionary *dictionaryFromFile = [NSDictionary dictionaryWithContentsOfFile:filePath];
    NSLog(@"从文件中读取到的字典为:%@",dictionaryFromFile);
}

输出结果为:

2020-10-30 17:58:34.469548+0800 FoundationDemo[47972:1807344] 成功写入文件,路径为:/Users/xiejiapei/Library/Developer/CoreSimulator/Devices/4E4809CA-E567-4D3A-8ADE-790075200303/data/Containers/Data/Application/62175E05-6FFD-4EEF-A872-3C08B6FBACB4/Documents/jia.plist
2020-10-30 17:58:34.469723+0800 FoundationDemo[47972:1807344] 从文件中读取到的字典为:{
    4 = 5;
    age = 22;
    name = XieJiaPei;
}
d、字典排序
- (void)compareDictionary
{
    NSDictionary *numberDict = @{@"Xie": @22, @"Liu": @18, @"Zou": @19};
    
    // compare:
    NSArray *newKeys = [numberDict keysSortedByValueUsingSelector:@selector(compare:)];
    NSLog(@"集合元素自身的排序方法(compare:),字典通过比较值将key排序后为:%@", newKeys);
    
    // block:
    NSDictionary *stringDict = @{@"Xie": @"apple", @"Liu": @"Banana", @"Zou": @"watermelon"};
    newKeys = [stringDict keysSortedByValueUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2)
    {
        if ([obj1 length] > [obj2 length])
        {
            return NSOrderedDescending;
        }
        if ([obj1 length] < [obj2 length])
        {
            return NSOrderedAscending;
        }
        return NSOrderedSame;
    }];
    NSLog(@"通过代码块排序,定义比较大小的标准:字符串越长越大,排序后key为:%@", newKeys);
}

输出结果为:

2020-10-30 18:10:00.621205+0800 FoundationDemo[48152:1816838] 集合元素自身的排序方法(compare:),字典通过比较值将key排序后为:(
    Liu,
    Zou,
    Xie
)
2020-10-30 18:10:00.621368+0800 FoundationDemo[48152:1816838] 通过代码块排序,定义比较大小的标准:字符串越长越大,排序后key为:(
    Xie,
    Liu,
    Zou
)
e、字典过滤
- (void)filteredDictionary
{
    NSDictionary *numberDict = @{@"Xie": @22, @"Liu": @18, @"Zou": @19};
    
    NSSet *keySet = [numberDict keysOfEntriesPassingTest:^BOOL(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop)
    {
        return ([obj intValue] < 20);
    }];
    NSLog(@"真羡慕,你俩都好小呀:%@",keySet);
}

输出结果为:

2020-10-30 18:13:51.339440+0800 FoundationDemo[48212:1821809] 真羡慕,你俩都好小呀:{(
    Liu,
    Zou
)}
f、可变字典
- (void)mutableDictionary
{
    NSDictionary *numberDict = @{@"Xie": @22, @"Liu": @18, @"Zou": @19};
    NSMutableDictionary *mutableDict = [NSMutableDictionary dictionaryWithDictionary:numberDict];
    
    mutableDict[@"Xie"] = @"love Liu";
    NSLog(@"覆盖值后,字典为:%@",mutableDict);
    
    mutableDict[@"marray"] = @"baby";
    NSLog(@"添加新元素后,字典为:%@",mutableDict);
    
    [mutableDict addEntriesFromDictionary:@{@"Lin":@21}];
    NSLog(@"添加另外一个字典后,字典为:%@",mutableDict);
    
    [mutableDict removeObjectForKey:@"Xie"];
    NSLog(@"删除元素后,字典为:%@",mutableDict);
}

输出结果为:

2020-10-30 18:19:20.392259+0800 FoundationDemo[48302:1826112] 覆盖值后,字典为:{
    Liu = 18;
    Xie = "love Liu";
    Zou = 19;
}
2020-10-30 18:19:20.392358+0800 FoundationDemo[48302:1826112] 添加新元素后,字典为:{
    Liu = 18;
    Xie = "love Liu";
    Zou = 19;
    marray = baby;
}
2020-10-30 18:19:20.392443+0800 FoundationDemo[48302:1826112] 添加另外一个字典后,字典为:{
    Lin = 21;
    Liu = 18;
    Xie = "love Liu";
    Zou = 19;
    marray = baby;
}
2020-10-30 18:19:20.392513+0800 FoundationDemo[48302:1826112] 删除元素后,字典为:{
    Lin = 21;
    Liu = 18;
    Zou = 19;
    marray = baby;
}

3、NSArray

a、创建数组
NSArray *aArray = @[@1, @2, @3];
NSArray<NSString *> *bArray = @[@"2", @"4", @"3", @"1"];
NSArray *cArray = [NSArray arrayWithObjects:@1, @"XieJiaPei", person, nil];
NSArray *dArray = [NSArray arrayWithObjects:@1, @"XieJiaPei", nil, @5, person, nil];
NSLog(@"原始数组A为:%@",aArray);
NSLog(@"原始数组B为:%@",bArray);
NSLog(@"原始数组A为:%@",cArray);
NSLog(@"原始数组C为:%@",dArray);

输出结果为:

2020-10-21 16:48:29.731149+0800 BasicGrammarDemo[1505:46009] 原始数组A为:(
    1,
    2,
    3
)
2020-10-21 16:48:29.731213+0800 BasicGrammarDemo[1505:46009] 原始数组B为:(
    2,
    4,
    3,
    1
)
2020-10-21 16:48:29.731286+0800 BasicGrammarDemo[1505:46009] 原始数组A为:(
    1,
    XieJiaPei,
    "<PersonClass: 0x600002dfa140>"
)
2020-10-21 16:48:29.731345+0800 BasicGrammarDemo[1505:46009] 原始数组C为:(
    1,
    XieJiaPei
)
b、从数组中取值
NSString *index1IncArray = [cArray objectAtIndex:1];
NSNumber *index0IncArray = cArray[0];
NSLog(@"数组C中下标0的值为:%@,下标1的值为:%@",index0IncArray,index1IncArray);

NSArray *array = @[@"xie",@"jia",@"pei",@"fan",@"yi",@"cheng",@"lin",@"feng",@"mian"];
NSArray *newArray = [array objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(2, 3)]];
NSLog(@"获取索引从2~5的元素组成的新集合:%@",newArray);

NSLog(@"获取元素在集合中的位置:%lu",(unsigned long)[array indexOfObject:@"xie"]);

array = [array arrayByAddingObjectsFromArray:newArray];
NSLog(@"向array数组的最后追加另一个数组的所有元素:%@",array);

array = [array subarrayWithRange:NSMakeRange(5, 3)];
NSLog(@"索引为5~8处的所有元素:%@",array);

输出结果为:

2020-10-21 16:48:29.765873+0800 BasicGrammarDemo[1505:46009] 数组C中下标0的值为:1,下标1的值为:XieJiaPei

2020-10-30 15:08:34.786959+0800 FoundationDemo[45297:1678179] 获取索引从2~5的元素组成的新集合:(
    pei,
    fan,
    yi
)
2020-10-30 15:08:34.787054+0800 FoundationDemo[45297:1678179] 获取元素在集合中的位置:0
2020-10-30 15:08:34.787135+0800 FoundationDemo[45297:1678179] 向array数组的最后追加另一个数组的所有元素:(
    xie,
    jia,
    pei,
    fan,
    yi,
    cheng,
    lin,
    feng,
    mian,
    pei,
    fan,
    yi
)
2020-10-30 15:08:34.787201+0800 FoundationDemo[45297:1678179] 索引为5~8处的所有元素:(
    cheng,
    lin,
    feng
)
c、给数组排序
NSArray *sortedArray = [bArray sortedArrayUsingSelector:@selector(compare:)];
NSLog(@"集合元素自身的排序方法(compare:),数组B排序后为:%@", sortedArray);

NSArray *sortedArrayByFunction = [bArray sortedArrayUsingFunction:intSort context:nil];
NSLog(@"通过函数排序,数组B排序后为:%@", sortedArrayByFunction);

NSArray *sortedArrayByBlock = [bArray sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2)
{
    if ([obj1 integerValue] > [obj2 integerValue])
    {
        return NSOrderedDescending;
    }
    if ([obj1 intValue] < [obj2 intValue])
    {
        return NSOrderedAscending;
    }
    return NSOrderedSame;
}];
NSLog(@"通过代码块排序,数组B排序后为:%@", sortedArrayByBlock);

NSInteger intSort(id num1, id num2, void *context)
{
    int v1 = [num1 intValue];
    int v2 = [num2 intValue];
    if (v1 < v2)
        return NSOrderedAscending;
    else if (v1 > v2)
        return NSOrderedDescending;
    else
        return NSOrderedSame;
}

输出结果为:

2020-10-30 15:19:30.831961+0800 FoundationDemo[45456:1686606] 集合元素自身的排序方法(compare:),数组B排序后为:(
    1,
    2,
    3,
    4
)
2020-10-30 15:19:30.832052+0800 FoundationDemo[45456:1686606] 通过函数排序,数组B排序后为:(
    1,
    2,
    3,
    4
)
2020-10-30 15:19:30.832179+0800 FoundationDemo[45456:1686606] 通过代码块排序,数组B排序后为:(
    1,
    2,
    3,
    4
)
d、让数组过滤数据
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF matches %@", @"[3-9]+"];
NSArray *filteredArray = [bArray filteredArrayUsingPredicate:predicate];
NSLog(@"数组B过滤数据(只留下3-9之间的数据)后为:%@", filteredArray);

输出结果为:

2020-10-21 16:53:27.058488+0800 BasicGrammarDemo[1615:51718] 数组B过滤数据(只留下3-9之间的数据)后为:(
    4,
    3
)
e、可变数组
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:@[@"xie",@"jia",@"pei",@"fan",@"yi",@"cheng"]];

// 向集合最后添加一个元素
[mutableArray addObject:@"liu"];
// 向集合尾部添加多个元素
[mutableArray addObjectsFromArray:@[@"ying",@"chi"]];
NSLog(@"向集合最后位置添加元素后数组为:%@",mutableArray);

// 指定位置插入一个元素
[mutableArray insertObject:@"GuanYu" atIndex:1];
// 指定位置插入多个元素
[mutableArray insertObjects:@[@"ZhangFei",@"ZhaoYun"] atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)]];
NSLog(@"指定位置插入元素后数组为:%@",mutableArray);

// 删除最后一个元素
[mutableArray removeLastObject];
// 删除指定索引处的元素
[mutableArray removeObjectAtIndex:5];
// 删除2~5处元素
[mutableArray removeObjectsInRange:NSMakeRange(2, 3)];
NSLog(@"删除元素后数组为:%@",mutableArray);

// 替换索引为2处的元素
[mutableArray replaceObjectAtIndex:2 withObject:@"MaChao"];
NSLog(@"替换可变数组中的数据后为:%@",mutableArray);

输出结果为:

2020-10-30 17:00:55.532047+0800 FoundationDemo[46981:1758054] 向集合最后位置添加元素后数组为:(
    xie,
    jia,
    pei,
    liu,
    ying,
    chi
)
2020-10-30 17:00:55.532186+0800 FoundationDemo[46981:1758054] 指定位置插入元素后数组为:(
    xie,
    ZhangFei,
    ZhaoYun,
    GuanYu,
    jia,
    pei,
    liu,
    ying,
    chi
)
2020-10-30 17:00:55.532264+0800 FoundationDemo[46981:1758054] 删除元素后数组为:(
    xie,
    ZhangFei,
    liu,
    ying
)
2020-10-30 17:00:55.532336+0800 FoundationDemo[46981:1758054] 替换可变数组中的数据后为:(
    xie,
    ZhangFei,
    MaChao,
    ying
)
f、数组的拷贝
NSArray *shallowCopyArray = [bArray copy];
NSLog(@"原数组为不可变数组——使用copy——结果数组为不可变数组,比较是否相等的结果为:%@", shallowCopyArray == bArray ? @"相等" : @"不相等");
NSLog(@"原数组为不可变数组——使用copy——结果数组为不可变数组,比较元素是否相等的结果为:%@", shallowCopyArray[3] == bArray[3] ? @"相等" : @"不相等");

NSMutableArray *mutableCopyArray = [bArray mutableCopy];
NSLog(@"原数组为不可变数组——使用mutableCopy——结果数组为可变数组,比较是否相等的结果为:%@", mutableCopyArray == bArray ? @"相等" : @"不相等");

NSMutableArray *copyArray = [mutableCopyArray copy];
NSLog(@"原数组为可变数组——使用copy——结果数组为可变数组,比较是否相等的结果为:%@", copyArray == mutableCopyArray ? @"相等" : @"不相等");

NSMutableArray *anotherMutableCopyArray = [mutableCopyArray mutableCopy];
NSLog(@"原数组为可变数组——使用mutableCopy——结果数组为可变数组,比较是否相等的结果为:%@", anotherMutableCopyArray == mutableCopyArray ? @"相等" : @"不相等");

输出结果为:

2020-10-21 17:16:15.239156+0800 BasicGrammarDemo[2026:73856] 原数组为不可变数组——使用copy——结果数组为不可变数组,比较是否相等的结果为:相等
2020-10-21 17:16:15.239212+0800 BasicGrammarDemo[2026:73856] 原数组为不可变数组——使用copy——结果数组为不可变数组,比较元素是否相等的结果为:相等
2020-10-21 17:16:15.239280+0800 BasicGrammarDemo[2026:73856] 原数组为不可变数组——使用mutableCopy——结果数组为可变数组,比较是否相等的结果为:不相等
2020-10-21 17:16:15.239336+0800 BasicGrammarDemo[2026:73856] 原数组为可变数组——使用copy——结果数组为可变数组,比较是否相等的结果为:不相等
2020-10-21 17:16:15.239401+0800 BasicGrammarDemo[2026:73856] 原数组为可变数组——使用mutableCopy——结果数组为可变数组,比较是否相等的结果为:不相等
g、数组的遍历

一般的遍历方式包括for循环NSEnumeratorfor in。比较特殊的遍历方式enumerateObjectsUsingBlock是通过block回调,在子线程中遍历,对象的回调次序是乱序的,而且调用线程会等待该遍历过程完成。这几个遍历方式中for in性能最好,for循环较低, 多线程遍历方式是性能最差的。

for (NSString *string in bArray)
{
    NSLog(@"使用快速遍历,字符串为:%@",string);
}

NSEnumerator *enumerator = [bArray objectEnumerator];
id object;
while (object = [enumerator nextObject])
{
    NSLog(@"使用顺序枚举器,数值为:%@",object);
}

NSEnumerator *reverseEnumerator = [bArray reverseObjectEnumerator];
while (object = [reverseEnumerator nextObject])
{
    NSLog(@"使用逆序枚举器,数值为:%@" , object);
}

输出结果为:

2020-10-30 15:26:21.535811+0800 FoundationDemo[45562:1691741] 使用快速遍历,字符串为:2
2020-10-30 15:26:21.535861+0800 FoundationDemo[45562:1691741] 使用快速遍历,字符串为:4
2020-10-30 15:26:21.535928+0800 FoundationDemo[45562:1691741] 使用快速遍历,字符串为:3
2020-10-30 15:26:21.535992+0800 FoundationDemo[45562:1691741] 使用快速遍历,字符串为:1

2020-10-30 15:26:21.536155+0800 FoundationDemo[45562:1691741] 使用顺序枚举器,数值为:2
2020-10-30 15:26:21.536255+0800 FoundationDemo[45562:1691741] 使用顺序枚举器,数值为:4
2020-10-30 15:26:21.536402+0800 FoundationDemo[45562:1691741] 使用顺序枚举器,数值为:3
2020-10-30 15:26:21.536514+0800 FoundationDemo[45562:1691741] 使用顺序枚举器,数值为:1

2020-10-30 15:26:21.536622+0800 FoundationDemo[45562:1691741] 使用逆序枚举器,数值为:1
2020-10-30 15:26:21.536748+0800 FoundationDemo[45562:1691741] 使用逆序枚举器,数值为:3
2020-10-30 15:26:21.536884+0800 FoundationDemo[45562:1691741] 使用逆序枚举器,数值为:4
2020-10-30 15:26:21.536991+0800 FoundationDemo[45562:1691741] 使用逆序枚举器,数值为:2
h、写入文件
NSArray<NSString *> *bArray = @[@"2", @"4", @"3", @"1"];

NSString *documentPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *filePath = [documentPath stringByAppendingFormat:@"/%@",@"xie.plist"];
if ( [bArray writeToFile:filePath atomically:YES] )
{
    NSLog(@"成功写入文件,路径为:%@",filePath);
}

NSArray *arrayFromFile = [NSArray arrayWithContentsOfFile:filePath];
NSLog(@"从文件中读取到的数组为:%@",arrayFromFile);

输出结果为:

2020-10-30 16:40:54.419610+0800 FoundationDemo[46618:1741321] 成功写入文件,路径为:/Users/xiejiapei/Library/Developer/CoreSimulator/Devices/4E4809CA-E567-4D3A-8ADE-790075200303/data/Containers/Data/Application/27126598-B9C0-4156-BC10-D3EAC6697F7F/Documents/xie.plist
2020-10-30 16:40:54.419790+0800 FoundationDemo[46618:1741321] 从文件中读取到的数组为:(
    2,
    4,
    3,
    1
)
I、整体调用方法
- (void)performSelector
{
    PersonClass *person = [[PersonClass alloc] init];
    NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:@[person,person,person,person]];
    
    // 对集合元素整体调用方法
    [mutableArray makeObjectsPerformSelector:@selector(printPetPhrase:) withObject:@"锤子"];
    NSLog(@"对集合元素整体调用方法:%@",mutableArray);
    
    // 迭代集合内指定范围内元素,并使用该元素来执行代码块
    [mutableArray enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, 2)] options:NSEnumerationReverse usingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
         NSLog(@"正在处理第%ld个元素:%@" , idx , obj);
    }];
}

- (void)printPetPhrase:(NSString *)petPhrase
{
    NSLog(@"你的口头禅是什么呀?%@",petPhrase);
}

输出结果为:

2020-10-30 17:22:03.303271+0800 FoundationDemo[47347:1775321] 你的口头禅是什么呀?锤子
2020-10-30 17:22:03.303360+0800 FoundationDemo[47347:1775321] 你的口头禅是什么呀?锤子
2020-10-30 17:22:03.303433+0800 FoundationDemo[47347:1775321] 你的口头禅是什么呀?锤子
2020-10-30 17:22:03.303490+0800 FoundationDemo[47347:1775321] 你的口头禅是什么呀?锤子
2020-10-30 17:22:03.303692+0800 FoundationDemo[47347:1775321] 正在处理第2个元素:<PersonClass: 0x6000031ac880>
2020-10-30 17:22:03.303758+0800 FoundationDemo[47347:1775321] 正在处理第1个元素:<PersonClass: 0x6000031ac880>
J、数组去除重复元素

利用NSSet特性, 放入集合自动去重。这种方法更快,利用NSSet不会添加重复元素的特性。

NSArray *selected = [deleteDuplicateSet allObjects];

不过去重的数组没有进行排序,如果需要排序,可以使用NSSortDescriptor类。

NSSet *deleteDuplicateSet = [NSSet setWithArray:self.switchAlbumSelectList];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"displayName" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
NSArray *selected = [deleteDuplicateSet sortedArrayUsingDescriptors:sortDescriptors];

利用NSDictionaryAllKeysAllValues)方法可以将NSArray中的元素存入一个字典,然后利用AllKeys或者AllValues取得字典的所有键或值,这些键或值都是去重的。结果为无序的,也就是说不包含原有顺序,可自行加入排序算法。

NSArray *originalArr = @[@1, @2, @3, @1, @3];
NSMutableDictionary *dictM = [NSMutableDictionary dictionary];
for (NSNumber *n in originalArr) {
[dict setObject:n forKey:n];
}
NSLog(@"%@",[dictM allValues]);

通过valueForKeyPath去重只需一行代码。

NSArray *originalArr = @[@1, @2, @3, @1, @3];
NSArray *result = [originalArr valueForKeyPath:@"@distinctUnionOfObjects.self"];

开辟新的内存空间,判断是否存在,若不存在则添加到数组中,得到最终结果的顺序不发生变化。

// 只能通过这种方式去重,而不能使用字典、Set,因为要保证批量上传的顺序按照选择时候的顺序
NSMutableArray *selected = [NSMutableArray array];
for (UCARPhotoModel *photo in self.switchAlbumSelectList)
{
  if (![selected containsObject:photo])
  {
    [selected addObject:photo];
  }
}

六、NSDate

1、Date

a、创建日期
- (void)date
{
    // 使用时间间隔创建日期
    NSTimeInterval secondsPerDay = 24 * 60 * 60;// 一天
    NSDate *tomorrow1 = [[NSDate alloc] initWithTimeIntervalSinceNow:secondsPerDay];// 明天
    NSDate *yesterday1 = [[NSDate alloc] initWithTimeIntervalSinceNow:-secondsPerDay];// 昨天
    NSLog(@"使用时间间隔创建日期,昨天:%@,明天:%@",yesterday1, tomorrow1);
    
    // 通过添加时间间隔创建日期
    NSDate *today = [NSDate date];
    NSDate *tomorrow2 = [today dateByAddingTimeInterval:secondsPerDay];// 明天
    NSDate *yesterday2 = [today dateByAddingTimeInterval:-secondsPerDay];// 昨天
    NSLog(@"使用时间间隔创建日期,昨天:%@,明天:%@",yesterday2, tomorrow2);

    // 从1970年1月1日开始,20年之后的日期
    NSDate *twentyYearsDate = [NSDate dateWithTimeIntervalSince1970:secondsPerDay*366*20];
    NSLog(@"从1970年1月1日开始,20年之后的日期:%@",twentyYearsDate);
}

输出结果为:

2020-09-24 11:05:35.266263+0800 BasicGrammarDemo[97687:17759303] 使用时间间隔创建日期,昨天:2020-09-23 03:05:35 +0000,明天:2020-09-25 03:05:35 +0000
2020-09-24 11:05:35.266383+0800 BasicGrammarDemo[97687:17759303] 通过添加时间间隔创建日期,昨天:2020-09-23 03:05:35 +0000,明天:2020-09-25 03:05:35 +0000
2020-09-24 11:32:29.711559+0800 BasicGrammarDemo[98039:17779918] 从1970年1月1日开始,20年之后的日期:1990-01-16 00:00:00 +0000
b、比较日期

可以使用isEqualToDate:compare:laterDate:earlierDate:方法。

- (void)compareDate
{
    NSDate *today = [NSDate date];// 今天
    NSDate *tomorrow = [today dateByAddingTimeInterval:24 * 60 * 60];// 明天
    
    // 看看两个日期是否在一分钟(60秒)内
    // fabs:求一个实数的绝对值
    if (fabs([tomorrow timeIntervalSinceDate:today]) < 60)
    {
        NSLog(@"两个日期在一分钟(60秒)内");
    }
    else
    {
        NSLog(@"两个日期不在一分钟(60秒)内");
    }
    
    
    // 之前、相同、之后
    switch ([today compare:tomorrow])
    {
        case NSOrderedAscending:
            NSLog(@"之前");
            break;
        case NSOrderedSame:
            NSLog(@"相等");
            break;
        case NSOrderedDescending:
            NSLog(@"之后");
            break;
    }
    
    // 返回比较的两个日期中更早的那个
    today = [today earlierDate:tomorrow];
    NSLog(@"较早的日期:%@",today);
    
    // 返回比较的两个日期中更晚的那个
    today = [today laterDate:tomorrow];
    NSLog(@"较晚的日期:%@",today);
}

输出结果为:

2020-09-24 14:40:57.125611+0800 BasicGrammarDemo[99895:17885247] 两个日期不在一分钟(60秒)内
2020-09-24 14:40:57.125685+0800 BasicGrammarDemo[99895:17885247] 之前
2020-09-24 14:40:57.125769+0800 BasicGrammarDemo[99895:17885247] 较早的日期:2020-09-24 06:40:57 +0000
2020-09-24 14:40:57.125844+0800 BasicGrammarDemo[99895:17885247] 较晚的日期:2020-09-25 06:40:57 +0000
c、日期格式
// 日期格式
- (void)dateFormat
{
    // 时间的本地化
    NSDate *today = [NSDate date];
    NSLocale *locale = [NSLocale currentLocale];// 系统当前的Locale
    [today descriptionWithLocale:locale];
    NSLog(@"时间的本地化:%@",today);
    
    
    
    // 创建两个NSLocale,分别代表中国、美国
    NSLocale *locales[] = {[[NSLocale alloc] initWithLocaleIdentifier:@"zh_CN"], [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]};
        
    // 设置NSDateFormatter的日期、时间风格
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateStyle:NSDateFormatterShortStyle];
    [dateFormatter setTimeStyle:NSDateFormatterShortStyle];
    
    // NSLocale
    [dateFormatter setLocale:locales[0]];
    // 设置自定义的格式模板
    [dateFormatter setDateFormat:@"公元yyyy年MM月DD日 HH时mm分"];
    // stringFromDate
    NSString* stringFromDate = [dateFormatter stringFromDate:today];
    NSLog(@"stringFromDate 时间的格式化:%@",stringFromDate);
    
    // dateFromString
    NSString *dateString = @"2020-01-18 06:50:24";
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    NSDate *dateFromString = [formatter dateFromString:dateString];
    NSLog(@"dateFromString 时间的格式化:%@",dateFromString);
}

输出结果为:

2020-09-24 14:55:48.071631+0800 BasicGrammarDemo[309:17900007] 时间的本地化:2020-09-24 06:55:48 +0000
2020-09-24 14:55:48.072018+0800 BasicGrammarDemo[309:17900007] stringFromDate 时间的格式化:公元2020年09月268日 14时55分
2020-09-24 15:11:59.105726+0800 BasicGrammarDemo[764:17914033] dateFromString 时间的格式化:2020-01-17 22:50:24 +0000
d、时间戳
- (void)dateInterval
{
    NSDate *today = [NSDate date];// 今天
    NSDate *tomorrow = [today dateByAddingTimeInterval:24 * 60 * 60];// 明天
    
    // 时间差
    double interval = [today timeIntervalSinceDate:tomorrow];
    NSLog(@"与明天的时间差:%f",interval);
    
    // 与现在的时间差
    interval = [today timeIntervalSinceNow];
    NSLog(@"与现在的时间差:%f",interval);
}

输出结果为:

2020-09-24 14:40:57.126282+0800 BasicGrammarDemo[99895:17885247] 与明天的时间差:-86400.000000
2020-09-24 14:40:57.126339+0800 BasicGrammarDemo[99895:17885247] 与现在的时间差:-0.000070

2、Calendar

a、创建日历
- (void)calendar
{
    // 创建日历对象
    NSCalendar *currentCalendar = [NSCalendar currentCalendar];
    
    // local、usersCalendar和currentCalendar是相等的,尽管它们是不同的对象
    NSCalendar *usersCalendar = [[NSLocale currentLocale] objectForKey:NSLocaleCalendar];

    // 还可以通过为所需日历指定标识符来创建任意日历对象
    // 获取代表公历的Calendar对象
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
}
b、通过日历获取不同时间字段的信息
- (void)calendar
{
    NSDate *date = [NSDate date];
    NSLog(@"现在日期为:%@",date);
    // 还可以通过为所需日历指定标识符来创建任意日历对象
    // 获取代表公历的Calendar对象
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    // 定义一个时间字段的旗标,指定将会获取指定年、月、日、时、分、秒的信息
    unsigned unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitWeekday;
    
    // 获取不同时间字段的信息
    NSDateComponents *components = [gregorian components:unitFlags fromDate:date];
    NSLog(@"年:%ld 月:%ld ",(long)components.year,(long)components.month);
}

输出结果为:

2020-09-24 11:17:01.315888+0800 BasicGrammarDemo[97860:17769221] 现在日期为:2020-09-24 03:17:01 +0000
2020-09-24 11:17:01.316009+0800 BasicGrammarDemo[97860:17769221] 年:2020 月:9 
c、通过日历设置各时间字段的数值
// 设置各时间字段的数值
NSDateComponents *newComponents = [[NSDateComponents alloc] init];
newComponents.year = 2020;
newComponents.month = 10;
newComponents.day = 1;

// 恢复NSDate
date = [gregorian dateFromComponents:newComponents];
NSLog(@"设置的日期为:%@",date);

输出结果为:

2020-09-24 11:17:01.316112+0800 BasicGrammarDemo[97860:17769221] 设置的日期为:2020-10-17 16:00:00 +0000
d、日期组件
- (void)dateComponents
{
    // 从日期获取组件
    NSDate *today = [NSDate date];
    // 获取代表公历的Calendar对象
    NSCalendar *decompose = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    // 指定将会获取指定周、日的信息
    NSDateComponents *weekdayComponents = [decompose components:(NSCalendarUnitDay | NSCalendarUnitWeekday) fromDate:today];
    
    NSInteger day = [weekdayComponents day];
    NSInteger newWeekday = [weekdayComponents weekday];
    NSLog(@"今天是:%@",today);
    NSLog(@"从日期获取组件 day:%ld, newWeekday:%ld",(long)day,(long)newWeekday);


    // 从组件创建日期
    NSDateComponents *components = [[NSDateComponents alloc] init];
    [components setDay:2];// 星期一
    [components setWeekdayOrdinal:1];// 这个月的第一个星期一
    [components setMonth:10];
    [components setYear:2020];
    NSDate *getDate = [decompose dateFromComponents:components];
    NSLog(@"从组件创建日期:%@",getDate);
}

输出结果为:

2020-09-24 15:09:33.838392+0800 BasicGrammarDemo[724:17912053] 今天是:2020-09-24 07:09:33 +0000
2020-09-24 15:09:33.838503+0800 BasicGrammarDemo[724:17912053] 从日期获取组件 day:24, newWeekday:5
2020-09-24 15:09:33.838631+0800 BasicGrammarDemo[724:17912053] 从组件创建日期:2020-10-01 16:00:00 +0000
e、计算日期
- (void)calculateDate
{
    NSDate *today = [[NSDate alloc] init];
    NSDate *tomorrow = [[NSDate alloc] initWithTimeIntervalSinceNow:24 * 60 * 60];
    NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];

    // 增加一个半小时后
    NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
    [offsetComponents setHour:1];
    [offsetComponents setMinute:30];
    NSDate *endOfWorldWar3 = [gregorian dateByAddingComponents:offsetComponents toDate:today options:0];
    NSLog(@"现在的时间是:%@",today);
    NSLog(@"一个半小时后就是第三次世界大战的结束时间:%@",endOfWorldWar3);
    
    // 通过减去日期来获取前一周的星期天 9月24日为周四,则上周日为9月20日,具有与原始日期相同的小时、分钟和秒
    NSDateComponents *weekdayComponents = [gregorian components:NSCalendarUnitWeekday fromDate:today];
    NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
    // 从当前日期减去的天数,公历中星期日的值是1,所以减去1,如果今天是星期日,则减去0天
    [componentsToSubtract setDay:(0 - ([weekdayComponents weekday] - 1))];
    NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];
    NSLog(@"通过减去日期来获取前一周的星期天:%@",beginningOfWeek);
    
    // 获取两个日期之间的差异
    NSUInteger unitFlags = NSCalendarUnitDay | NSCalendarUnitMonth;
    NSDateComponents *components = [gregorian components:unitFlags fromDate:today  toDate:tomorrow options:0];
    NSInteger months = [components month];
    // 输出两个日期day差数为0,因为8.5小时不到1天
    NSInteger days = [components day];
    NSLog(@"获取两个日期之间的差异,days:%ld,months:%ld",(long)days,(long)months);
}

输出结果为:

2020-09-24 15:27:18.050866+0800 BasicGrammarDemo[1024:17927076] 现在的时间是:2020-09-24 07:27:18 +0000
2020-09-24 15:27:18.050986+0800 BasicGrammarDemo[1024:17927076] 一个半小时后就是第三次世界大战的结束时间:2020-09-24 08:57:18 +0000
2020-09-24 15:27:18.051097+0800 BasicGrammarDemo[1024:17927076] 通过减去日期来获取前一周的星期天:2020-09-20 07:27:18 +0000
2020-09-24 15:27:18.051178+0800 BasicGrammarDemo[1024:17927076] 获取两个日期之间的差异,days:1,months:0

七、NSTimer

1、不重复的timer

// 在默认模式(NSDefaultRunLoopMode)下,用当前NSRunLoop对象自动注册新计时器
- (void)startTimer
{
    // 计时器在2秒后由运行循环自动触发,然后从运行循环中删除
    [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(targetMethod:) userInfo:self.userInfo repeats:NO];
}

- (void)targetMethod:(NSTimer *)theTimer
{
    NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"];
    NSLog(@"开始日期:%@",startDate);
}

- (NSDictionary *)userInfo
{
    return @{@"StartDate": [NSDate date]};
}

如果创建非重复计时器,它会自动停止。输出结果为:

2020-09-24 10:31:01.237970+0800 BasicGrammarDemo[97131:17724123] 开始日期:2020-09-24 02:30:59 +0000

2、重复的timer

- (void)startRepeatingTimer
{
    // 取消之前存在的timer
    [_repeatingTimer invalidate];
    
    // 创建新的timer
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(targetMethod:) userInfo:self.userInfo repeats:YES];
    _repeatingTimer = timer;
}

如果创建重复计时器,将计数器的repeats设置为YES的时候,self的引用计数会加1,因此可能会导致self(即viewController)不能释放,所以必须在viewDidDisappear方法里将计数器timer停止,否则可能会导致内存泄露,停止后,一定要将timer赋空,否则还是没有释放,会造成不必要的内存开销。

- (void)viewDidDisappear:(BOOL)animated
{
    NSLog(@"退出了当前页面,销毁了定时器");
    [self stopRepeatingTimer];
}

- (void)stopRepeatingTimer
{
    // 将计数器timer停止,否则可能会导致内存泄露
    [self.repeatingTimer invalidate];
    
    // 停止后,一定要将timer赋空,否则还是没有释放,会造成不必要的内存开销
    self.repeatingTimer = nil;
}

当再次进入定时器页面,重新开启定时器。

- (void)viewWillAppear:(BOOL)animated
{
    NSLog(@"进入定时器页面,重新开启定时器");
    
    // 开启定时器
    [self.repeatingTimer setFireDate:[NSDate distantPast]];//很远的过去
}

输出结果为:

2020-09-24 10:39:10.396329+0800 BasicGrammarDemo[97268:17732297] 开始日期:2020-09-24 02:39:06 +0000
2020-09-24 10:39:10.896330+0800 BasicGrammarDemo[97268:17732297] 开始日期:2020-09-24 02:39:06 +0000
2020-09-24 10:39:11.243983+0800 BasicGrammarDemo[97268:17732297] 退出了当前页面,销毁了定时器
2020-09-24 10:39:13.011582+0800 BasicGrammarDemo[97268:17732297] 进入定时器页面,重新开启定时器

发现定时器被销毁了,无法重新开启,所以可以使用viewWillDisappear替代viewDidDisappear里的实现。

// 在页面消失的时候关闭定时器,然后等页面再次打开的时候,又开启定时器
- (void)viewWillDisappear:(BOOL)animated
{
    // 关闭定时器
    [self.repeatingTimer setFireDate:[NSDate distantFuture]]; //很远的将来
    NSLog(@"退出了当前页面,只是关闭定时器未销毁,再次进入可重新启动");
}

输出结果为:

2020-09-24 10:41:46.070295+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000
2020-09-24 10:41:46.570290+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000
2020-09-24 10:41:46.879144+0800 BasicGrammarDemo[97329:17735552] 退出了当前页面,只是关闭定时器未销毁,再次进入可重新启动
2020-09-24 10:41:48.834727+0800 BasicGrammarDemo[97329:17735552] 进入定时器页面,重新开启定时器
2020-09-24 10:41:48.837701+0800 BasicGrammarDemo[97329:17735552] 开始日期:2020-09-24 02:41:44 +0000

3、Invocation + RunLoop

只使用invocation创建计时器。

- (void)createUnregisteredTimer
{
    // 1、根据方法来初始化NSMethodSignature
    // 方法签名中保存了方法的名称/参数/返回值,协同NSInvocation来进行消息的转发
    NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(invocationMethod:)];
    
    // 2、其实NSInvocation就是将一个方法变成一个对象
    // NSInvocation中保存了方法所属的对象/方法名称/参数/返回值
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
    
    // 设置方法调用者
    [invocation setTarget:self];
    
    // 设置方法名称,这里的方法名一定要与方法签名类中的方法一致
    [invocation setSelector:@selector(invocationMethod:)];
    
    NSDate *startDate = [NSDate date];
    // 设置方法参数,这里的Index要从2开始,因为0跟1已经被占据了,分别是self(target),selector
    [invocation setArgument:&startDate atIndex:2];
    
    // 3、调用invoke方法
    [invocation invoke];
    
    // 使用invocation创建计时器
    NSTimer *timer = [NSTimer timerWithTimeInterval:0.5 invocation:invocation repeats:YES];
    self.unregisteredTimer = timer;
    //[self addTimerToRunLoop];// 未添加到runloop中时
}

- (void)invocationMethod:(NSDate *)date
{
    NSLog(@"调用日期为:%@", date);
}

输出结果显示尽管计时器被配置为重复,但在触发一次之后,即被停止。

2020-09-24 10:45:21.267890+0800 BasicGrammarDemo[97383:17739828] 调用日期为:2020-09-24 02:45:21 +0000

现在将timer添加到run loop中。当前线程是主线程时,某些UI事件,比如ScrollView正在拖动,将会RunLoop切换成 NSEventTrackingRunLoopMode 模式,添加到RunLoop中的Timer就不会执行。

为了设置一个不被UI干扰的Timer,我们需要手动创建一个Timer,然后使用RunLoopaddTimer:forMode:方法来把Timer按照指定的模式加入到RunLoop中。

这里使用 NSRunLoopCommonModes 模式,这个模式相当于 NSDefaultRunLoopModeNSEventTrackingRunLoopMode 的结合。

// 将timer添加到run loop中
- (void)addTimerToRunLoop
{
    if (self.unregisteredTimer != nil)
    {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        [runLoop addTimer:self.unregisteredTimer forMode:NSDefaultRunLoopMode];
    }
}

打开[self addTimerToRunLoop]语句的注释,输出结果为:

2020-09-24 10:49:05.506717+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
2020-09-24 10:49:06.006756+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
2020-09-24 10:49:06.506797+0800 BasicGrammarDemo[97429:17743337] 调用日期为:2020-09-24 02:49:04 +0000
.......

4、Fire Date + RunLoop

- (void)startFireDateTimer
{
    // 用日期初始化计时器
    NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
    
    // 尽管计时器被配置为重复,但在countedTimerFireMethod触发三次之后,它将停止
    NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate interval:0.5 target:self selector:@selector(countedTimerFireMethod:) userInfo:self.userInfo repeats:YES];
   
    self.timerCount = 1;
    
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    [runLoop addTimer:timer forMode:NSDefaultRunLoopMode];
}

// 给计时器计算调用次数
- (void)countedTimerFireMethod:(NSTimer *)theTimer
{
    NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"];
    NSLog(@"开始日期: %@,调用次数: %lu", startDate, (unsigned long)self.timerCount);
    
    // 这将使计时器在触发三次后失效
    self.timerCount++;
    if (self.timerCount > 3)
    {
        [theTimer invalidate];
    }
}

输出结果为:

2020-09-24 10:50:43.824386+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 1
2020-09-24 10:50:44.323420+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 2
2020-09-24 10:50:44.823579+0800 BasicGrammarDemo[97467:17746749] 开始日期: 2020-09-24 02:50:42 +0000,调用次数: 3

八、NSPredicate

1、谓词语法

下面方法都是区分大小写的,如果要不区分大小写,则可以在运算符后面使用[c]

AND、&&:逻辑与
OR ||                     逻辑或
NOT !                    逻辑非

字符串比较运算符:
BEGINSWITH                检查某个字符串是否以指定的某个子串开头
ENDSWITH                  检查某个字符串是否以指定的某个子串结尾
CONTAINS                  检查某个字符串是否包含指定的某个子串
LIKE                      检查某个字符串是否匹配指定的字符串模板
MATCHES                   检查某个字符串是否匹配指定的正则表达式

操作集合的运算符:
ANY SOME                  指定只要集合中任意一个元素满足条件,即可返回YES。
ALL                       指定所有元素满足才返回YES。
NONE                      指定没有任何元素满足条件才返回YES。
IN                        只有当左边的表达式或值出现在右边的集合中才会返回YES。

数组:
array[index]              返回array数组中索引为index处的元素
array[FIRST]              返回array数组中第一个元素
array[LAST]               返回array数组中最后一个元素
array[SIZE]               返回array数组中元素的个数。

直接量:
FALSE NO                  逻辑假
TRUE YES                  逻辑真
NULL NIL                  代表一个空值
SELF                      代表正在被判断的对象
"text"或'text'            代表字符串
数组                      数组元素用英文字符隔开。eg:{'keli','zhangsan','lisi','wangwu'}
数值直接量                 包括整数、小数、科学计数法

2、正则表达式语法

^             指出一个字符串的开始
$             指出一个字符串的结束
"^iOS"        以iOS开头
"iOS$"        以iOS结尾
"^apple$"     开始和结尾都是apple的字符串,这个是唯一的,实际上就是apple
"apple"       包含apple
*  +  ?       重复出现的次数
?             0~1次
+             1~n次
*             0~n次
"ab*"         一个a后面跟着0~n个b
"ab+"         一个a后面跟着至少一个b
"ab?"         一个a后面跟着0~1个b
"a?b+$"       末尾有0~1个a跟着1~n个b
{}            表示重复的具体范围
"ab{4}"       一个a跟着4个b
"ab{1,}"      一个a跟着至少1个b
"ab{3,5}"     一个a跟着3~5个b
*             可以用{0,}表示
+             可以用{1,}表示
?             可以用{0,1}表示
|             或
"a|b"         一个字符串里有a或b
"(a|bcd)ef"   aef或bcdef
"(a|b)+c"     一串a和b混合的字符串后面跟一个c;
[ ]           表示在括号内的众多字符中,选择1-n个括号内的符合语法的字符作为结果
"[ab]"        一个a或b(相当于"a|b");
"[a-d]"       a到d中的一个(相当于"a|b|c|d"或者"[abcd]")
"^[a-zA-Z]"   以字母开头
"[0-9]a"      a前有一位数字
"[a-zA-Z0-9]$"以一个字母或数字结束
.             任意字符
"a.[a-z]"     a后面跟一个任意字符和一个小写字母
"^.{5}$"      长度为5的字符串
"@[^a-zA-Z]@" 在方括号里用^表示不希望出现的字符,^应在方括号里的第一位。表示两个@中不应该出现字母
"\d"          一个数字字符
"\D"          一个非数字字符
"\w "         包括下划线的任何单词字符
"\W"          匹配任何非单词字符
\             iOS中书写正则表达式,碰到转义字符,多加一个\

3、包含关系

a、是否在数组之中
- (void)inArrayDemo
{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF IN %@",@[@"先生女士",@"妙不可言",@"哈哈哈哈哈"]];
    BOOL result = [predicate evaluateWithObject:@"哈哈哈哈哈"];
    if (result)
    {
        NSLog(@"哈哈哈哈哈在数组中");
    }
}

输出结果为:

2020-09-24 16:59:50.674351+0800 ChecksumsWarning[2412:18002210] 哈哈哈哈哈在数组中
b、字符匹配
- (void)characterMatch
{
    NSString *prefix = @"prefix";
    NSString *suffix = @"suffix";
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF like[c] %@",[[prefix stringByAppendingString:@"*"] stringByAppendingString:suffix]];
    NSLog(@"predicate = %@", [predicate predicateFormat]);
    BOOL result = [predicate evaluateWithObject:@"prefixxxxxxsuffix"];
    if (result)
    {
        NSLog(@"字符匹配成功");
    }
    else
    {
        NSLog(@"字符匹配失败");
    }
}

输出结果为:

2020-09-24 17:23:59.032000+0800 ChecksumsWarning[2770:18022215] predicate = SELF LIKE[c] "prefix*suffix"
2020-09-24 17:23:59.033539+0800 ChecksumsWarning[2770:18022215] 字符匹配成功

4、数据过滤

a、比较大小
- (void)greaterThanDemo
{
    NSArray* array = @[@101,@200,@50,@5,@25,@12];
    NSLog(@"原数组:%@",array);
    // 创建谓词,要求该对象自身的值大于50
    NSPredicate *predicateThan50 = [NSPredicate predicateWithFormat:@"SELF > 50"];
    // 使用谓词执行过滤,过滤后只剩下值大于50的集合元素
    NSArray *filteredArray = [array filteredArrayUsingPredicate:predicateThan50];
    NSLog(@"数组过滤后只剩下值大于50的集合元素:%@",filteredArray);
}

输出结果为:

2020-09-24 16:18:24.591968+0800 ChecksumsWarning[1783:17966853] 原数组:(
    101,
    200,
    50,
    5,
    25,
    12
)
2020-09-24 16:18:24.592186+0800 ChecksumsWarning[1783:17966853] 数组过滤后只剩下值大于50的集合元素:(
    101,
    200
)
b、以特定字符开始
- (void)beginswithLetterDemo
{
    // 过滤掉不是以b开始的字符串
    NSMutableArray *letters = [@[@"Abc",@"Bbb",@"Ca"] mutableCopy];
    NSPredicate *predictForArray = [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
    NSArray *beginWithB = [letters filteredArrayUsingPredicate:predictForArray];
    NSLog(@"过滤掉不是以b开始的字符串:%@",beginWithB);
}

输出结果为:

2020-09-24 17:04:15.974855+0800 ChecksumsWarning[2479:18006076] 过滤掉不是以b开始的字符串:(
    Bbb
)

5、占位符

a、占位符参数
- (void)placeholderDemo
{
    NSString *name = @"name";
    NSString *value = @"齐天大圣";
    NSDictionary *ditc = @{@"name":@"我是齐天大圣孙悟空水帘洞花果山大王"};
    // 创建谓词,该谓词中包含了2个占位符,相当于创建了谓词表达式 "name CONTAINS '齐天大圣'" 字典中的键为name的值是否包含"齐天大圣"
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K contains %@",name, value];
    // 使用谓词执行判断
    BOOL isContain = [predicate evaluateWithObject:ditc];
    if (isContain)
    {
        NSLog(@"字典中的键为name的值包含齐天大圣");
    }
    else
    {
        NSLog(@"字典中的键为name的值不包含齐天大圣");
    }
}

输出结果为:

2020-09-24 16:18:24.592350+0800 ChecksumsWarning[1783:17966853] 字典中的键为name的值包含齐天大圣
b、设置变量值
- (void)SUBSTRdemo
{
    // $SUBSTR相当于一个变量,需要我们调用时为它设置值
    NSPredicate* predicateTemplate = [NSPredicate predicateWithFormat:@"%K CONTAINS $SUBSTR" , @"number"];
    // 使用NDDictionary指定SUBSTR的值为'50',这就相当于创建了谓词表达式"pass CONTAINS '50'"
    NSPredicate* predicate = [predicateTemplate predicateWithSubstitutionVariables:[NSDictionary dictionaryWithObjectsAndKeys:@"50",@"SUBSTR", nil]];
    // 使用谓词执行判断
    NSDictionary *ditc = @{@"number":@"50000123432425432"};
    BOOL isContain = [predicate evaluateWithObject:ditc];
    if (isContain)
    {
        NSLog(@"字典中的键为number的值包含50");
    }
    else
    {
        NSLog(@"字典中的键为number的值不包含50");
    }
}

输出结果为:

2020-09-24 16:35:53.575536+0800 ChecksumsWarning[1992:17978505] 字典中的键为number的值包含50

6、正则表达式

- (void)regularExpressionsDemo
{
    NSArray *array = @[@"TATACCATGGGCCATCATCATCATCATCATCATCATCATCATCACAG",
                       @"CGGGATCCCTATCAAGGCACCTCTTCG", @"CATGCCATGGATACCAACGAGTCCGAAC",
                       @"CAT", @"CATCATCATGTCT", @"DOG"];
    
    // 查找包含至少3个“CAT”序列重复的字符串,但后面没有“CA”
    NSPredicate *catPredicate = [NSPredicate predicateWithFormat:@"SELF MATCHES '.*(CAT){3,}(?!CA).*'"];
    NSArray *filteredArray = [array filteredArrayUsingPredicate:catPredicate];
    NSLog(@"查找包含至少3个CAT序列重复的字符串,但后面没有CA:%@",filteredArray);
}

输出结果为:

2020-09-24 16:40:32.491094+0800 ChecksumsWarning[2084:17983367] 查找包含至少3个“CAT”序列重复的字符串,但后面没有“CA”:(
    CATCATCATGTCT
)

7、空值

- (void)nullPredicateDemo
{
    NSString *firstName = @"Xie";
    NSArray *array = @[ @{ @"lastName" : @"JiaPei" }, @{ @"firstName" : @"Wang", @"lastName" : @"ErDe", @"birthday":[NSDate date]},@{ @"firstName" : @"Xie", @"lastName" : @"LingYun", @"birthday":[NSDate date]}];
    
    // 姓为Xie或者为空
    NSPredicate *predicateForNull = [NSPredicate predicateWithFormat:@"(firstName == %@) || (firstName = nil)", firstName];
    // 使用谓词执行判断
    NSArray *filteredArray = [array filteredArrayUsingPredicate:predicateForNull];
    NSLog(@"过滤后的数组为: %@", filteredArray);
    
    BOOL ok = [predicateForNull evaluateWithObject: [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"firstName"]];
    if (ok)
    {
        NSLog(@"存在姓为Xie或者为空");
    }
    else
    {
        NSLog(@"不存在姓为Xie或者为空");
    }
}

输出结果为:

2020-09-24 16:51:12.268705+0800 ChecksumsWarning[2267:17993506] 过滤后的数组为: (
        {
        lastName = JiaPei;
    },
        {
        birthday = "2020-09-24 08:51:12 +0000";
        firstName = Xie;
        lastName = LingYun;
    }
)
2020-09-24 16:51:12.268825+0800 ChecksumsWarning[2267:17993506] 存在姓为Xie或者为空

8、复合谓词

- (void)compoundPredicateDemo
{
    NSPredicate *predicate1 = [NSPredicate predicateWithFormat:@"SELF > 10"];
    NSLog(@"predicate1 = %@", [predicate1 predicateFormat]);
    NSPredicate *predicate2 = [NSPredicate predicateWithFormat:@"SELF < 50"];
    NSLog(@"predicate2 = %@", [predicate2 predicateFormat]);
    
    // NSAndPredicateType 多个谓词表达式之间添加AND,NSOrPredicateType 多个谓词表达式之间添加OR
    NSCompoundPredicate *compound = [[NSCompoundPredicate alloc] initWithType:NSAndPredicateType subpredicates:@[predicate1, predicate2]];
    NSLog(@"compound = %@", [compound predicateFormat]);
    
    BOOL result = [compound evaluateWithObject:@20];
    if (result)
    {
        NSLog(@"20在区间(20,50)内");
    }
    else
    {
        NSLog(@"20不在区间(20,50)内");
    }
}

输出结果为:

2020-09-24 17:17:16.746394+0800 ChecksumsWarning[2669:18016834] predicate1 = SELF > 10
2020-09-24 17:17:16.746510+0800 ChecksumsWarning[2669:18016834] predicate2 = SELF < 50
2020-09-24 17:17:16.746617+0800 ChecksumsWarning[2669:18016834] compound = SELF > 10 AND SELF < 50
2020-09-24 17:17:16.746715+0800 ChecksumsWarning[2669:18016834] 20在区间(20,50)内

9、Core Data中的使用

- (void)coreDataPredicate
{
    NSManagedObjectContext *managedObjectContext;
    
    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];
    
    NSInteger salaryLimit = 100;
    // 查找收入超过指定金额的员工
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"salary > %@", salaryLimit];
    [request setPredicate:predicate];
    
    // 查询结果
    NSError *error;
    NSArray *resultArray = [managedObjectContext executeFetchRequest:request error:&error];
}

Demo

Demo在我的Github上,欢迎下载。
FoundationGrammarDemo

参考文献

相关文章

网友评论

      本文标题:IOS基础:OC的Foundation语法

      本文链接:https://www.haomeiwen.com/subject/ftclmktx.html