美文网首页
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