美文网首页
第六章、oc的语言高级阶段

第六章、oc的语言高级阶段

作者: 冲浪小子 | 来源:发表于2018-03-15 16:14 被阅读0次

    1,copy内存管理

    #import "ViewController.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
    
        /*
         内存管理原则:
         一次alloc 对应一次release
         一次retain 对应一次 release
         一次copy 对应一次release
         有加就有减
         
         总结:
         如果是浅拷贝:不会生成新的对象,但是系统就会对原来的对象进行retain,
         所以需要对原来的对象进行一次
         
         如果是深拷贝:会生成新的对象,系统不会对原来的对象进行retain,但是因为生成了新的对象,所以我们需要对新的对象进行release
         */
    
        //1.创建一个不可变字符串
        NSString *str = [[NSString alloc]initWithFormat:@"lnj"];
        NSLog(@"str = %lu", [str retainCount]);
        
        /*
      
         */
        //不会生成新的对象,但是需要注意,正是因为不会生产新的对象,所以系统会对以前的对象进行一次retain
        //如果是浅拷贝,那么系统就会对原来的对象进行retain
        
        NSString *str2 = [str copy];
        NSLog(@"str = %lu", [str retainCount]);
        
        [str release];
        [str release];
        
        //深拷贝:会生成新的对象,正是因为会生成新的对象,所以系统不会对以前的对象进行retain,但是因为生成了新的对象,所以我们需要对新的对象进行release
        NSMutableString *strM = [str mutableCopy];
        NSLog(@"str = %lu", [str retainCount]);
        NSLog(@"strM = %lu", [strM retainCount]);
        
        NSLog(@"%p - %p", str, strM);
        [strM release];
        [str release];
        
    }
    @end
    

    数组NSArray和MutableArray

    1,NSArray的基本概念

    #import <Foundation/Foundation.h>
    #import "Person.h"
    
    int main(int argc, const char * argv[]) {
    
        /*
    //    NSArray *arr = [[NSArray alloc] init];
    //    NSArray *arr = [NSArray arrayWithObject:@"lnj"];
        // 数组中的nil是结束符
        NSArray *arr = [NSArray arrayWithObjects:@"lnj", @"lmj" ,@"jjj", @"cp", nil];
        NSLog(@"%@", arr);
        */
        
        /*
        Person *p  = [Person new];
        NSObject *obj = [NSObject new];
        NSArray *arr = [NSArray arrayWithObjects:p, obj, @"lnj", nil];
        NSLog(@"arr = %@", arr);
        
        NSLog(@"count = %lu", [arr count]);
        
        NSLog(@"last = %@", [arr lastObject]);
        NSLog(@"first = %@", [arr firstObject]);
        NSLog(@"arr[1] = %@", [arr objectAtIndex:1]);
         */
        
        /*
        NSArray *arr = [NSArray arrayWithObjects:@"lnj", @"lmj", @"jjj", @"zs", nil];
        if([arr containsObject:@"zs"])
        {
            NSLog(@"arr中包含zs");
        }else
        {
            NSLog(@"arr中不包含zs");
        }
         */
        
        // 创建数组简写
        NSString *str = @"lnj";
    //    NSArray *arr = [NSArray arrayWithObjects:@"lnj", @"lmj", @"jjj", nil];
        NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
        // 获取数组元素的简写
        NSLog(@"%@", [arr objectAtIndex:0]);
        NSLog(@"%@", arr[0]);
        return 0;
    }
    

    2,NSArray遍历

    #import <Foundation/Foundation.h>
    #import "Person.h"
    
    int main(int argc, const char * argv[]) {
    
    //    NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
        
        /*
        // 常规遍历
        for (int i = 0; i < arr.count; ++i) {
            NSLog(@"arr[%i] = %@", i, arr[i]);
        }
         
         */
        
        
        // 如果是OC数组可以使用OC中的增强for循环来遍历
        // 逐个取出arr中的元素, 将取出的元素赋值给obj
        // 注意: obj的类型可以根据数组中元素的类型来写, 不一定要写NSObject
        for (NSString *obj in arr) {
            NSLog(@"obj = %@", obj);
        }
        
        
        /*
        // 使用OC数组的迭代器来遍历
        // 每取出一个元素就会调用一次block
        // 每次调用block都会将当前取出的元素和元素对应的索引传递给我们
        // obj就是当前取出的元素, idx就是当前元素对应的索引
        // stop用于控制什么时候停止遍历
        [arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            if (idx == 1) {
                *stop = YES;
            }
            NSLog(@"obj = %@, idx = %lu", obj, idx);
        }];
         */
        
        
        Person *p1 = [Person new];
        Person *p2 = [Person new];
        Person *p3 = [Person new];
        Person *p4 = [Person new];
        
        NSArray *arr = @[p1, p2, p3, p4];
        /*
        [arr enumerateObjectsUsingBlock:^(Person *obj, NSUInteger idx, BOOL *stop) {
            [obj say];
        }];
        */
        
        // 如果使用OC数组存储对象, 可以调用OC数组的方法让数组中所有的元素都执行指定的方法
        // 注意点: 如果数组中保存的不是相同类型的数据, 并且没有相同的方法, 那么会报错
    //    [arr makeObjectsPerformSelector:@selector(say)];
        
        // withObject: 需要传递给调用方法的参数
        [arr makeObjectsPerformSelector:@selector(sayWithName:) withObject:@"lnj"];
        return 0;
    }
    
    
    Person类
    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    - (void)say;
    
    - (void)sayWithName:(NSString *)name;
    @end
    
    Person.m类
    #import "Person.h"
    
    @implementation Person
    
    -(void)say
    {
        NSLog(@"加油");
    }
    
    - (void)sayWithName:(NSString *)name
    {
        NSLog(@"%@ 加油", name);
    }
    @end
    
    

    3,NSArray排序

    #import <Foundation/Foundation.h>
    #import "Person.h"
    
    int main(int argc, const char * argv[]) {
    
        /*
        NSArray *arr = @[@10, @20, @5, @7, @15];
        NSLog(@"排序前: %@", arr);
        // 注意: 想使用compare方法对数组中的元素进行排序, 那么数组中的元素必须是Foundation框架中的对象, 也就是说不能是自定义对象
        NSArray *newArr = [arr sortedArrayUsingSelector:@selector(compare:)];
        NSLog(@"排序后: %@", newArr);
        */
        
        Person *p1 = [Person new];
        p1.age = 10;
        
        Person *p2 = [Person new];
        p2.age = 20;
        
        Person *p3 = [Person new];
        p3.age = 5;
        
        Person *p4 = [Person new];
        p4.age = 7;
        
        NSArray *arr = @[p1, p2, p3, p4];
        NSLog(@"排序前: %@", arr);
        // 按照人的年龄进行排序
        // 不能使用compare:方法对自定义对象进行排序
    //    NSArray *newArr = [arr sortedArrayUsingSelector:@selector(compare:)];
        
        // 该方法默认会按照升序排序
        NSArray *newArr = [arr sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(Person *obj1, Person *obj2) {
            // 每次调用该block都会取出数组中的两个元素给我们
            // 二分
    //        NSLog(@"obj1 = %@, obj2 = %@", obj1, obj2);
    //        return obj1.age > obj2.age;
    //        上面的是升序排列,下面的是降序排列
            return obj1.age < obj2.age;
            /*
            if (obj1.age > obj2.age) {
                // 5 4
                return NSOrderedDescending;
            }else if(obj1.age < obj2.age)
            {
                // 4 5
                return NSOrderedAscending;
            }else
            {
                return NSOrderedSame;
            }
             */
        }];
        NSLog(@"排序后: %@", newArr);
        return 0;
    }
    

    4,NSArray和NSString之间转换

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
    //    NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
        // 需求: 用-将所有的姓名连接起来生成一个字符串
        
        /*
        // 1.定义一个可变字符串保存拼接之后的结果
        NSMutableString *strM = [NSMutableString string];
        // 2.遍历数组, 取出数组中的每一个元素, 将元素添加到可变字符串中
        for (NSString *str in arr) {
            [strM appendString:str];
            // 3.每次添加完毕之后再添加一个-
            [strM appendString:@"-"];
        }
        [strM deleteCharactersInRange:NSMakeRange(strM.length - 1, 1)];
        NSLog(@"strM = %@", strM);
         */
        
        /*
        NSString *str = [arr componentsJoinedByString:@"**"];
        NSLog(@"str = %@", str);
         
        */
        
        // 通过一个字符串生成一个数组
        // 也叫做字符串切割
        NSString *str = @"lnj**lmj**jjj";
        NSArray *arr = [str componentsSeparatedByString:@"**"];
        NSLog(@"arr = %@", arr);
        
    //    打印出来的效果
    //    arr = (
    //           lnj,
    //           lmj,
    //           jjj
    //           )
        return 0;
    }
    

    5,NSArray文件读写

    #import <Foundation/Foundation.h>
    #import "Person.h"
    
    int main(int argc, const char * argv[]) {
        // 1.将数组写入到文件中
        /*
        NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
        // 其实如果将一个数组写入到文件中之后, 本质是写入了一个XML文件
        // 在iOS开发中一般情况下我们会将XML文件的扩展名保存为plist
        BOOL flag = [arr writeToFile:@"/Users/xiaomage/Desktop/abc.plist" atomically:YES];
        NSLog(@"flag = %i", flag);
         */
        
        Person *p1 = [Person new];
        p1.age = 10;
        
        Person *p2 = [Person new];
        p2.age = 20;
        
        Person *p3 = [Person new];
        p3.age = 5;
        
        Person *p4 = [Person new];
        p4.age = 7;
        
        NSArray *arr = @[p1, p2, p3, p4];
    //     注意:writeToFile只能写入数组中保存的元素都是Foundation框架中的类创建的对象, 如果保存的是自定义对象那么不能写入
        BOOL flag = [arr writeToFile:@"/Users/xiaomage/Desktop/person.plist" atomically:YES];
        NSLog(@"flag = %i", flag);
        
        
        // 2.从文件中读取一个数组
        /*
        NSArray *newArray = [NSArray arrayWithContentsOfFile:@"/Users/xiaomage/Desktop/abc.plist"];
        NSLog(@"%@", newArray);
        */
        
        return 0;
    }
    

    6,NSMutableArray的基本概念

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        // 创建一个空的数组
        NSMutableArray *arrM = [NSMutableArray array];
        NSLog(@"%@", arrM);
        // 如何添加
        [arrM addObject:@"lnj"];
        // 将指定数组中的元素都取出来, 放到arrM中
        // 并不是将整个数组作为一个元素添加到arrM中
        [arrM addObjectsFromArray:@[@"lmj", @"jjj"]];
        // 注意: 以下是将整个数组作为一个元素添加
    //    [arrM addObject:@[@"lmj", @"jjj"]];
        NSLog(@"%@", arrM);
        // 如何插入
        [arrM insertObject:@"xcq" atIndex:1];
        NSLog(@"%@", arrM);
        
        NSRange range = NSMakeRange(2, 2);
        NSIndexSet *set = [NSIndexSet indexSetWithIndexesInRange:range];
        // 插入一组数据, 指定数组需要插入的位置, 和插入多少个
        [arrM insertObjects:@[@"A", @"B"] atIndexes:set];
         NSLog(@"%@", arrM);
    //    打印的结果是:
    //    NSMutableArray[1221:29098] (
    //                                lnj,
    //                                xcq,
    //                                A,
    //                                B,
    //                                lmj,
    //                                jjj
    //                                )
        /*
        // 如何删除
        [arrM removeObjectAtIndex:0];
         NSLog(@"%@", arrM);
        
        [arrM removeLastObject];
        NSLog(@"%@", arrM);
        指定的一个元素
        [arrM removeObject:@"A"];
         NSLog(@"%@", arrM);
        
        // 如何替换
        [arrM replaceObjectAtIndex:1 withObject:@"M"];
        NSLog(@"%@", arrM);
        
        // 如何获取
        NSLog(@"%@", [arrM objectAtIndex:0]);
        NSLog(@"%@", arrM[0]);
        
        // 替换
        arrM[0] = @"ZS";
        NSLog(@"%@", arrM);
        
        // 注意: 不能通过@[]来创建一个可变数组, 因为@[]创建出来的是一个不可变的数组
        // 如果把一个不可变数组当做一个可变数组来使用, 会引发一个运行时的错误
        NSMutableArray *arrM = @[@"lnj", @"lmj"];
        [arrM addObject:@"JJJ"];*/
        
        return 0;
    }
    

    7,NSDictionary

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        // 1.如何创建
    //    NSDictionary *dict = [NSDictionary dictionaryWithObject:@"lnj" forKey:@"name"];
    //    NSString *name = [dict objectForKey:@"name"];
    //    NSLog(@"name = %@", name);
        
        // 注意: key和value 是一一对应
    //    NSDictionary *dict = [NSDictionary dictionaryWithObjects:@[@"lnj", @"30", @"1.75"] forKeys:@[@"name", @"age", @"height"]];
    //    NSLog(@"%@ %@ %@", [dict objectForKey:@"name"], [dict objectForKey:@"age"], [dict objectForKey:@"height"]);
        
    //    NSDictionary *dict = @{key:value};
    //    NSDictionary *dict = @{@"name": @"lnj"};
    //    NSLog(@"%@", dict[@"name"]);
        
    //    NSDictionary *dict = @{@"name":@"lnj", @"age":@"30", @"height":@"1.75"};
    //    NSLog(@"%@ %@ %@", dict[@"name"], dict[@"age"], dict[@"height"]);
        
        // 2.字典的遍历
        NSDictionary *dict1 = @{@"name":@"lnj", @"age":@"30", @"height":@"1.75"};
        // 2.1如何获取字典中key和value的个数, 在字典中key称之为键, value称之为值
    //    打印的值为:3
        NSLog(@"count = %lu", [dict1 count]);
        
        /*
        for (int i = 0; i < dict.count; ++i) {
            // 获取字典中所有的key
            NSArray *keys = [dict allKeys];
            // 取出当前位置对应的key
    //        NSLog(@"%@", keys[i]);
            NSString *key = keys[i];
            NSString *value = dict[key];
            NSLog(@"key = %@, value = %@", key, value);
        }
         */
        
        /*
        // 如何通过forin遍历字典, 会将所有的key赋值给前面的obj
        for (NSString *key in dict) {
    //        NSLog(@"%@", key);
            NSString *value = dict[key];
            NSLog(@"key = %@, value = %@", key, value);
    
        }
         */
        
        /*
        [dict enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
            NSLog(@"key = %@, value = %@", key, obj);
        }];
         */
        
        // 3.字典文件读写
        NSDictionary *dict = @{@"name":@"lnj", @"age":@"30", @"height":@"1.75"};
        // XML 扩展名plist
        [dict writeToFile:@"/Users/xiaomage/Desktop/info.plist" atomically:YES];
        
        // 注意: 字典和数组不同, 字典中保存的数据是无序的
        NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:@"/Users/xiaomage/Desktop/info.plist"];
        NSLog(@"%@", newDict);
        
        
        NSArray *arr = @[@10, @20, @30, @5];
        [arr writeToFile:@"/Users/xiaomage/Desktop/abc.plist" atomically:YES];
        
        return 0;
    }
    

    8,NSMutableDictionary

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        /*
        // 1.创建一个空的字典
        NSMutableDictionary *dictM = [NSMutableDictionary  dictionary];
        NSLog(@"%@", dictM);
        // 2.如何添加
        [dictM setObject:@"lnj" forKey:@"name"];
        NSLog(@"%@", dictM);
        // 会将传入字典中所有的键值对取出来添加到dictM中
        [dictM setValuesForKeysWithDictionary:@{@"age":@"30", @"height":@"1.75"}];
        NSLog(@"%@", dictM);
        // 3.如何获取
        NSLog(@"name = %@", dictM[@"name"]);
        
        // 4.如何删除
        [dictM removeObjectForKey:@"name"];
        NSLog(@"%@", dictM);
    //    [dictM removeObjectsForKeys:@[@"age", @"height"]];
    //     NSLog(@"%@", dictM);
        // 5.如何修改
        // 如果利用setObject方法给同名的key赋值, 那么新值会覆盖旧值
    //    [dictM setObject:@"88" forKey:@"age"];
         dictM[@"age"] = @"88";
        NSLog(@"%@", dictM);
         */
        
        // 1.不能使用@{}来创建一个可变的字典
    //    NSMutableDictionary *dictM = @{@"name":@"lnj"};
    //    [dictM setObject:@"30" forKey:@"age"];
        
        
        // 2.如果是不可变数组, 那么key不能相同
        // 如果是不可变字典出现了同名的key, 那么后面的key对应的值不会被保存
        // 如果是在可变数组中, 后面的会覆盖前面的
        NSDictionary *dict = @{@"name":@"lmj", @"name":@"lnj"};
        NSLog(@"dict = %@", dict);
        
        NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithObjects:@[@"lmj", @"lnj"] forKeys:@[@"name", @"name"]];
        NSLog(@"dict = %@", dictM);
        
        return 0;
        
    //    打印的结果:
    //    2018-03-15 10:25:36.905934+0800 NSMutableDictionary[1757:46366] dict = {
    //        name = lmj;
    //    }
    //    2018-03-15 10:25:36.906294+0800 NSMutableDictionary[1757:46366] dict = {
    //        name = lnj;
    //    }
    }
    

    9,OC中的常用结构体

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        // 1.保存坐标的
    //    NSPoint;
    //    CGPoint point = NSMakePoint(10, 20);
        
        // 2.保存尺寸的
    //    NSSize;
    //    CGSize size = NSMakeSize(100, 50);
        
        // 3.保存坐标和尺寸
        NSRect;
        CGRect rect = NSMakeRect(10, 20, 100, 50);
        
        // 4.在开发中苹果推荐我们使用CG开头的结构体, 也就是说NS开头的结构体一般不用
        
        return 0;
    }
    

    10,NSNumber

    int main(int argc, const char * argv[]) {
    
        int age = 10;
        double number= 5.1;
        int value =  6;
    //    基本数据类型不能存入数组
    //    NSArray *arr =  @[age, number, value];
        // 1.将基本数据类型转换为对象类型
        NSNumber *ageN = [NSNumber numberWithInt:age];
        NSNumber *numberN = [NSNumber numberWithDouble:number];
        NSNumber *valueN = [NSNumber numberWithInt:value];
        
        NSArray *arr = @[ageN, numberN, valueN];
        NSLog(@"arr = %@", arr);
        
        // 2.将对象类型转换为基本数据类型
    //    int temp = [ageN intValue];
    //    double temp = [numberN doubleValue];
    //    NSLog(@"%f", temp);
        
        // 3.基本数据类型转换对象类型简写
        // 注意: 如果传入的是变量那么必须在@后面写上(), 如果传入的常量, 那么@后面的()可以省略
    //    NSNumber *temp = @(number);
        NSNumber *temp  =@10.10;
        NSLog(@"%@", temp);
        
        return 0;
    }
    

    11,NSValue

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
    //    typedef struct{
    //        int age;
    //        char *name;
    //        double _height;
    //    }Person;
    //
    //    Person p = {30, "lnj", 1.75};
    ////    结构体不包装不能存入数组,所以要用NSValue
    //    NSArray *arr = @[p];
        
        // 1.利用NSValue包装常用的结构体
        
    //    CGPoint point = NSMakePoint(10, 20);
    //    NSValue *value = [NSValue valueWithPoint:point];
    //    NSArray *arr1 = @[value];
    //    NSLog(@"%@", arr1);
        
        // 2.利用NSValue包装自定义的结构体
        typedef struct{
            int age;
            char *name;
            double height;
        }Person;
        
        Person p = {30, "lnj", 1.75};
        // valueWithBytes: 接收一个指针, 需要传递需要包装的结构体的变量的地址
        // objCType: 需要传递需要包装的数据类型
        NSValue *pValue = [NSValue valueWithBytes:&p objCType:@encode(Person)];
        NSArray *arr = @[pValue];
        NSLog(@"%@", arr);
        // 从NSValue中取出自定义的结构体变量
        Person res;
        [pValue getValue:&res];
        NSLog(@"age = %i, name = %s, height = %f", res.age, res.name, res.height);
        
        return 0;
    }
    

    12,NSDate

    int main(int argc, const char * argv[]) {
    
        // 1.NSDate创建和基本概念
        
        // 只要是通过date方法创建的时间对象, 对象中就保存了当前的时间
        NSDate *now = [NSDate date];
        NSLog(@"now = %@", now);
        // 在now的基础上追加多少秒
        NSDate *date1 = [now dateByAddingTimeInterval:10];
        NSLog(@"date = %@", date1);
    //    打印的结果是:
    //    2018-03-15 10:44:49.276294+0800 NSDate[1994:55461] now = Thu Mar 15 10:44:49 2018
    //    2018-03-15 10:44:49.276358+0800 NSDate[1994:55461] date = Thu Mar 15 10:44:59 2018
    
        
        // 1.获取当前所处的时区
        NSTimeZone *zone = [NSTimeZone systemTimeZone];
        // 2.获取当前时区和指定时区的时间差
        NSInteger seconds = [zone secondsFromGMTForDate:now];
        NSLog(@"seconds = %lu", seconds);
    //    打印结果:28800 也就是8个小时
        NSDate *newDate = [now dateByAddingTimeInterval:seconds];
        NSLog(@"newDate = %@", newDate);
    //    现在的时间8个小时
    
        // 2.时间格式化  NSDate --> NSString
     
        // xxxx年xx月xx日 xx小时xx分钟xx秒
        // xxxx/xx/xx  xx/xx/xx
        // xx/xx/xxxx  xx/xx/xx
        NSDate *now1 = [NSDate date];
        
        // 创建一个时间格式化对象
        NSDateFormatter *formatter1 = [[NSDateFormatter alloc] init];
        // 告诉时间格式化对象, 按照什么样的格式来格式化时间
        // yyyy 年
        // MM 月
        // dd 日
        // HH 24小时  hh 12小时
        // mm 分钟
        // ss 秒钟
        // Z 时区
    //    formatter.dateFormat = @"yyyy年MM月dd日 HH时mm分ss秒 Z";
        formatter1.dateFormat = @"MM-dd-yyyy HH-mm-ss";
        
        // 利用时间格式化对象对时间进行格式化
        NSString *res = [formatter1 stringFromDate:now1];
        NSLog(@"res = %@", res);
       
        // NSString --> NSDate
        NSString *str = @"2015-06-29 07:05:26 +0000";
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        // 注意: 如果是从NSString格式化为NSDate, 那么dateFormat的格式, 必须和字符串中的时间格式一致, 否则可能转换失败
        formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
        NSDate *date = [formatter dateFromString:str];
        NSLog(@"%@", date);
    
        return 0;
    }
    

    13,NSCalendar

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        // 1.获取当前时间的年月日时分秒
        /*
        // 获取当前时间
        NSDate *now = [NSDate date];
        NSLog(@"now = %@", now);
        // 日历
        NSCalendar *calendar1 = [NSCalendar currentCalendar];
        // 利用日历类从当前时间对象中获取 年月日时分秒(单独获取出来)
        // components: 参数的含义是, 问你需要获取什么?
        // 一般情况下如果一个方法接收一个参数, 这个参数是是一个枚举 , 那么可以通过|符号, 连接多个枚举值
        NSCalendarUnit type = NSCalendarUnitYear |
                              NSCalendarUnitMonth |
                              NSCalendarUnitDay |
                              NSCalendarUnitHour |
                             NSCalendarUnitMinute |
                            NSCalendarUnitSecond;
        NSDateComponents *cmps = [calendar1 components:type fromDate:now];
        NSLog(@"year = %ld", cmps.year);
        NSLog(@"month = %ld", cmps.month);
        NSLog(@"day = %ld", cmps.day);
        NSLog(@"hour = %ld", cmps.hour);
        NSLog(@"minute = %ld", cmps.minute);
        NSLog(@"second = %ld", cmps.second);
        
        打印的结果:
        2018-03-15 10:56:07.682445+0800 NSCalendar[2158:61248] now = Thu Mar 15 10:56:07 2018
        2018-03-15 10:56:07.683580+0800 NSCalendar[2158:61248] year = 2018
        2018-03-15 10:56:07.683630+0800 NSCalendar[2158:61248] month = 3
        2018-03-15 10:56:07.683652+0800 NSCalendar[2158:61248] day = 15
        2018-03-15 10:56:07.683664+0800 NSCalendar[2158:61248] hour = 10
        2018-03-15 10:56:07.683674+0800 NSCalendar[2158:61248] minute = 56
        2018-03-15 10:56:07.683684+0800 NSCalendar[2158:61248] second = 7
        */
    
        // 2.比较两个时间之间的差值, 比较相差多少年多少月多少日多少小时多少分钟多少秒
        
        // 2.1过去的一个时间
        NSString *str = @"2015-06-29 07:05:26 +0000";
        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        formatter.dateFormat = @"yyyy-MM-dd HH:mm:ss Z";
        NSDate *date = [formatter dateFromString:str];
        // 2.2当前的时间
        NSDate *now = [NSDate date];
    
        NSLog(@"date = %@", date);
        NSLog(@"now = %@", now);
    
        // 2.3比较两个时间
        NSCalendar *calendar = [NSCalendar currentCalendar];
        NSCalendarUnit type = NSCalendarUnitYear |
        NSCalendarUnitMonth |
        NSCalendarUnitDay |
        NSCalendarUnitHour |
        NSCalendarUnitMinute |
        NSCalendarUnitSecond;
        NSDateComponents *cmps = [calendar components:type fromDate:date toDate:now options:0];
        NSLog(@"%ld年%ld月%ld日%ld小时%ld分钟%ld秒钟", cmps.year, cmps.month, cmps.day, cmps.hour, cmps.minute, cmps.second);
    //    打印结果:
    //    2018-03-15 10:59:20.710963+0800 NSCalendar[2195:62513] date = Mon Jun 29 15:05:26 2015
    //    2018-03-15 10:59:20.711031+0800 NSCalendar[2195:62513] now = Thu Mar 15 10:59:20 2018
    //    2018-03-15 10:59:20.711341+0800 NSCalendar[2195:62513] 2年8月14日19小时53分钟54秒钟
        return 0;
    }
    

    14,NSFileManager文件管理

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        
        NSFileManager *manager = [NSFileManager defaultManager];
        // 1.判断一个文件或者文件夹是否存在
        /*
        BOOL flag = [manager fileExistsAtPath:@"/Users/xiaomage/Desktop/video/01-NSArray基本概念.mp4"];
        NSLog(@"flag = %i", flag);
         */
        
        // 2.判断一个文件是否存在, 并且判断它是否是一个文件夹
        /*
        // 注意: 该方法的返回值是说明传入的路径对应的文件或文件夹是否存在
        //       第二个参数是用于保存判断结果的, 如果是一个目录, 那么就会赋值为YES, 如果不是就赋值为NO
        BOOL dir = NO;
        BOOL flag = [manager fileExistsAtPath:@"/Users/xiaomage/Desktop/video/01-NSArray基本概念.mp4" isDirectory:&dir];
        NSLog(@"flag = %i, dir = %i", flag, dir);
         */
        
        // 3.获取文件或文件夹的属性
        /*
        NSDictionary *info = [manager attributesOfItemAtPath:@"/Users/xiaomage/Desktop/video/01-NSArray基本概念.mp4" error:nil];
        NSLog(@"info = %@", info);
         */
        
        // 4.获取文件夹中所有的文件
        /*
        // 注意:contentsOfDirectoryAtPath方法有一个弊端, 只能获取当前文件夹下所有的文件, 不能获取子文件夹下面的文件
        NSArray *res = [manager contentsOfDirectoryAtPath:@"/Users/xiaomage/Desktop/video" error:nil];
        NSLog(@"res = %@", res);
         */
        /*
    //    NSArray *res = [manager subpathsAtPath:@"/Users/xiaomage/Desktop/video"];
        NSArray *res = [manager subpathsOfDirectoryAtPath:@"/Users/xiaomage/Desktop/video" error:nil];
        NSLog(@"res = %@", res);
        
        // 作业: 要求计算一个文件夹中所有文件的大小
        // 注意: 如果通过attributesOfItemAtPath方法直接获取, 那么获取到的文件夹的大小不准确
        // 要想实现计算一个文件夹中所有文件的大小必须先拿到所有的文件, 然后再获取所有文件的大小, 然后再相加
        */
        
        // 5.创建文件夹
        /*
        // createDirectoryAtPath: 告诉系统文件夹需要创建到什么位置
        // withIntermediateDirectories: 如果指定的文件中有一些文件夹不存在, 是否自动创建不存在的文件夹
        // attributes: 指定创建出来的文件夹的属性
        // error: 是否创建成功, 如果失败会给传入的参数赋值
        // 注意: 该方法只能用于创建文件夹, 不能用于创建文件
         BOOL flag = [manager createDirectoryAtPath:@"/Users/xiaomage/Desktop/abc/lnj" withIntermediateDirectories:YES attributes:nil error:nil];
        NSLog(@"%i", flag);
         */
        
        // 6.创建文件
        // createFileAtPath: 指定文件创建出来的位置
        // contents : 文件中的内容
        // attributes: 创建出来的文件的属性
        
        // NSData : 二进制数据
        // 注意: 该方法只能用于创建文件, 不能用于创建文件夹
        NSString *str = @"江哥真帅";
        NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
        [manager createFileAtPath:@"/Users/xiaomage/Desktop/abc.txt" contents:data attributes:nil];
        
        return 0;
    }
    

    15,数组集合对象的内存管理

    #import <Foundation/Foundation.h>
    #import "Person.h"
    
    int main(int argc, const char * argv[]) {
    
        @autoreleasepool {
            
            /*
            // 1. 如果将一个对象添加到一个数组中, 那么数组会对对象进行一个retain
            Person *p = [Person new];
            NSLog(@"reatinCount = %lu", [p retainCount]);
            NSMutableArray *arrM = [[NSMutableArray alloc] init];
            
            [arrM addObject:p];
            NSLog(@"reatinCount = %lu", [p retainCount]);
            
            [p release];
            NSLog(@"reatinCount = %lu", [p retainCount]);
            // 当数组对象释放之后, 会给数组中所有的对象发送一条release消息
            [arrM release];
             */
            
            Person *p = [Person new]; // 1
            NSLog(@"reatinCount = %lu", [p retainCount]);
            NSMutableArray *arrM = [[NSMutableArray alloc] init];
            [arrM addObject:p]; // 2
            NSLog(@"reatinCount = %lu", [p retainCount]);
            
            [p release]; // 1
            // 当数组移除一个对象之后, 会给这个对象发送一条release消息
            [arrM removeObject:p];
        }
        return 0;
    }
    

    16,Copy基本使用

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        /*
         // 会生成一个新的对象
        NSString *srcStr = @"lnj";
        // 只要是拷贝出来的对象, 拷贝出来的对象中的内容和以前对象中的内容一致
        // "一般"情况下拷贝会生成一个新的对象
        // 为什么会产生一个新的对象 1.因为拷贝要求修改原来的对象不能影响到拷贝出来得对象 \
                                  修改拷贝出来的对象也不能影响到原来的对象, 所以需要生成一个新的对象 \
                                2.由于以前的对象是一个不可变的对象, 而通过mutableCopy拷贝出来的对象必须是一个可变的对象, 所以必须生成一个新的对象
        
        NSMutableString *copyStr = [srcStr mutableCopy];
        NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
        NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
         
         */
        
        /*
         //  会生成一个新的对象
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
        NSMutableString *copyStr = [srcStr mutableCopy];
        
        [srcStr appendString:@" cool"];
        NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
        NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
         */
        
        /*
         //  会生成一个新的对象
        NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
        NSString *copyStr = [srcStr copy];
        [srcStr appendString:@" cool"];
        NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
        NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
         */
        
    
        // 如果是通过不可变对象调用了copy方法, 那么不会生成一个新的对象
        // 原因: 因为原来的对象是不能修改的, 拷贝出来的对象也是不能修改的
        // 既然两个都不能修改, 所以永远不能影响到另外一个对象, 那么已经符合需求
        // 所以: OC为了对内存进行优化, 就不会生成一个新的对象
        NSString *srcStr = @"lnj";
        NSString *copyStr = [srcStr copy];
        NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
        
        /*
         正是因为调用copy方法有时候会生成一个新的对象, 有时候不会生成一个新的对象
         所以: 如果没有生成新的对象, 我们称之为浅拷贝, 本质就是指针拷贝
              如果生成了新的对象, 我们称之为深拷贝, 本质就是会创建一个新的对象
         */
        return 0;
    }
    

    17,Copy内存管理

    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
    
        @autoreleasepool {
            /*
            //NSString *str1 = @"lnj";
            char *cstr = "this is a c string";
            NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
            NSLog(@"str = %lu", [str1 retainCount]); // 1
            // 不会产生新对象, 会对原有对象进行一次retain
            NSString *str2 = [str1 copy]; // 2
            NSLog(@"str = %lu", [str1 retainCount]);
            
            // 注意点: 如果是浅拷贝, 那么会对拷贝的对象进行一次retain, 那么我们就需要对拷贝出来的对象进行一次release
            [str2 release]; // 1
            [str1 release]; // 0
             */
            
            char *cstr = "this is a c string";
            NSString *str1 = [[NSString alloc] initWithUTF8String:cstr];
            NSLog(@"str1 = %lu", [str1 retainCount]); // 1
            
            // 会生成一个新的对象
            NSMutableString *str2 = [str1 mutableCopy];
            NSLog(@"%p %p", str1, str2);
            NSLog(@"str2 = %lu", [str2 retainCount]); // 1
            
            [str1 release];
            [str2 release];
            
            /*
             内存管理的原则, 有加就有减
             一次alloc/retain/copy 对应一次release
             
             */
        }
        return 0;
    }
    

    18,Copy与Property

    int main(int argc, const char * argv[]) {
    
        
        // 1.copy的第一个用途, 防止外界修改内部的数据
        
        /*
        NSMutableString *temp = [NSMutableString stringWithFormat:@"lnj"];
        
        Person *p = [[Person alloc] init];
        p.name = temp;
        
        // 问题: 修改了外面的变量, 影响到了对象中的属性
        [temp appendString:@" cool"];
        
        NSLog(@"name = %@", p.name);
        
        // 记住: 以后字符串属性都用copy
         */
        
        /*
        __block int num = 10;
        void (^myBlock)() = ^{
            num = 20;
            NSLog(@"%i", num);
        };
        myBlock();
         */
        /*
        // block默认存储在栈中, 栈中的block访问到了外界的对象, 不会对对象进行retain
        // block如果在堆中, 如果在block中访问了外界的对象, 会对外界的对象进行一次retain
        Person *p = [[Person alloc] init];
        NSLog(@"retainCount = %lu", [p retainCount]);
        void (^myBlock)() = ^{
            NSLog(@"%@", p);
            NSLog(@"retainCount = %lu", [p retainCount]);
        };
        Block_copy(myBlock); // 将block转移到堆中
        myBlock();
         */
        
        // 2.可以使用copy保存block, 这样可以保住block中使用的外界对象的命
        /*
        // 避免以后调用block的时候, 外界的对象已经释放了
        Dog *d = [[Dog alloc] init]; // 1
        NSLog(@"retainCount = %lu", [d retainCount]);
        Person *p = [[Person alloc] init];
        p.pBlock = ^{
            // 2
            NSLog(@"%@", d);
        };
        NSLog(@"retainCount = %lu", [d retainCount]); // 2
    
        // 如果狗在调用block之前释放了, 那么程序就会崩溃
        [d release]; // 1
        
        p.pBlock();
        
        [p release];
         */
        
        // 3.注意点: copy block之后引发循环引用
        // 如果对象中的block又用到了对象自己, 那么为了避免内存泄露, 应该将对象修饰为__block
        __block Person *p = [[Person alloc] init]; // 1
        p.name = @"lnj";
        NSLog(@"retainCount = %lu", [p retainCount]);
        p.pBlock = ^{
            NSLog(@"name = %@", p.name); // 2
        };
        NSLog(@"retainCount = %lu", [p retainCount]);
        p.pBlock();
        
        [p release]; // 1
    //    [p release]; // 2B
        
        return 0;
    }
    
    
    Person.h
    #import <Foundation/Foundation.h>
    
    
    typedef void (^myBlock)();
    
    @interface Person : NSObject
    
    //@property (nonatomic, retain) NSString *name;
    @property (nonatomic, copy) NSString *name;
    
    // 注意: 如果是block使用copy并不是拷贝, 而是转移
    @property (nonatomic, copy) myBlock pBlock;
    @end
    

    19,自定义类实现copy

    • main.m类
    #import <Foundation/Foundation.h>
    #import "Person.h"
    #import "Student.h"
    
    int main(int argc, const char * argv[]) {
    
        /*
         1.以后想让自定义的对象能够被copy只需要遵守NSCopying协议
         2.实现协议中的- (id)copyWithZone:(NSZone *)zone
         3.在- (id)copyWithZone:(NSZone *)zone方法中创建一个副本对象, 然后将当前对象的值赋值给副本对象即可
         */
        
        Person *p = [[Person alloc] init];
        p.age =  30;
        p.name = @"lnj";
        NSLog(@"%@,%p", p,&p);
        Person *p2 = [p copy];
        Person *p3 = [p mutableCopy];
        
        NSLog(@"%@,%@,%p,%p", p2,p3,&p2,&p3);
    //    打印结果:
    //    2018-03-15 15:50:29.669328+0800 自定义类实现copy[4622:150414] name = lnj, age = 30,0x7fff5fbff6a8
    //    2018-03-15 15:50:29.669579+0800 自定义类实现copy[4622:150414] name = lnj, age = 30,name = lnj, age = 30,0x7fff5fbff6a0,0x7fff5fbff698
    //    2018-03-15 15:50:29.669684+0800 自定义类实现copy[4622:150414] stu = name = lnj, age = 30, height = 1.750000
    //    2018-03-15 15:50:29.669734+0800 自定义类实现copy[4622:150414] stu2 = name = lnj, age = 30, height = 1.750000
        
        Student *stu = [[Student alloc] init];
        stu.age = 30;
        stu.height = 1.75;
        stu.name = @"lnj";
        NSLog(@"stu = %@", stu);
        
        // 如果想让子类在copy的时候保留子类的属性, 那么必须重写copyWithZone方法, 在该方法中先调用父类创建副本设置值, 然后再设置子类特有的值
        Student *stu2 = [stu copy];
        NSLog(@"stu2 = %@", stu2);
        
        return 0;
    }
    
    • Person类
    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject<NSCopying, NSMutableCopying>
    
    @property (nonatomic, assign) int age;
    
    @property (nonatomic, copy) NSString *name;
    @end
    
    
    
    
    #import "Person.h"
    
    @implementation Person
    
    
    - (id)copyWithZone:(NSZone *)zone
    {
        // 1.创建一个新的对象
        Person *p = [[[self class] allocWithZone:zone] init];
        
        // 2.设置当前对象的内容给新的对象
        p.age = _age;
        p.name = _name;
        
        // 3.返回新的对象
        return p;
    }
    - (id)mutableCopyWithZone:(NSZone *)zone
    {
        // 1.创建一个新的对象
        Person *p = [[[self class] allocWithZone:zone] init];
        
        // 2.设置当前对象的内容给新的对象
        p.age = _age;
        p.name = _name;
        
        // 3.返回新的对象
        return p;
    }
    
    - (NSString *)description
    {
        return [NSString stringWithFormat:@"name = %@, age = %i", _name, _age];
    }
    @end
    
    • Student.h
    #import "Person.h"
    
    @interface Student : Person
    
    @property (nonatomic, assign) double height;
    @end
    
    
    
    
    #import "Student.h"
    
    @implementation Student
    
    - (id)copyWithZone:(NSZone *)zone
    {
        // 1.创建副本
    //    id obj = [[self class] allocWithZone:zone];
        id obj = [super copyWithZone:zone];
        // 2.设置数据给副本
    //    [obj setAge:[self age]];
    //    [obj setName:[self name]];
        [obj setHeight:_height];
        
        // 3.返回副本
        return obj;
    }
    
    - (NSString *)description
    {
        return [NSString stringWithFormat:@"name = %@, age = %i, height = %f", [self name], [self age], _height];
    }
    
    @end
    

    20,单例(宏定义抽取单例)

    int main(int argc, const char * argv[]) {
        Tools *t1 = [[Tools alloc] init]; //内部会调用allocWithZone
        Tools *t2 = [Tools new];// [[alloc] init]  allocWithZone
        Tools *t3 = [Tools shareTools];
        
        Tools *t4 = [t3 copy];
        Tools *t5 = [t3 mutableCopy];
        
        NSLog(@"%p, %p, %p, %p, %p", t1, t2, t3, t4, t5);
        
        Person *p1 = [Person sharePerson];
        Person *p2 = [Person sharePerson];
        Person *p3 = [Person sharePerson];
        
        NSLog(@"%p, %p, %p", p1 , p2, p3);
        // 如何判断当前是ARC还是MRC?
        // 可以在编译的时候判断当前是否是ARC
    #if __has_feature(objc_arc)
        NSLog(@"ARC");
    #else
        NSLog(@"MRC");
    #endif
        return 0;
    }
    
    • Singleton.h核心类
    
    // 以后就可以使用interfaceSingleton来替代后面的方法声明
    #define interfaceSingleton(name)  +(instancetype)share##name
    
    #if __has_feature(objc_arc)
    // ARC
    #define implementationSingleton(name)  \
    + (instancetype)share##name \
    { \
    name *instance = [[self alloc] init]; \
    return instance; \
    } \
    static name *_instance = nil; \
    + (instancetype)allocWithZone:(struct _NSZone *)zone \
    { \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
    _instance = [[super allocWithZone:zone] init]; \
    }); \
    return _instance; \
    } \
    - (id)copyWithZone:(NSZone *)zone{ \
    return _instance; \
    } \
    - (id)mutableCopyWithZone:(NSZone *)zone \
    { \
    return _instance; \
    }
    #else
    // MRC
    
    #define implementationSingleton(name)  \
    + (instancetype)share##name \
    { \
    name *instance = [[self alloc] init]; \
    return instance; \
    } \
    static name *_instance = nil; \
    + (instancetype)allocWithZone:(struct _NSZone *)zone \
    { \
    static dispatch_once_t onceToken; \
    dispatch_once(&onceToken, ^{ \
    _instance = [[super allocWithZone:zone] init]; \
    }); \
    return _instance; \
    } \
    - (id)copyWithZone:(NSZone *)zone{ \
    return _instance; \
    } \
    - (id)mutableCopyWithZone:(NSZone *)zone \
    { \
    return _instance; \
    } \
    - (oneway void)release \
    { \
    } \
    - (instancetype)retain \
    { \
    return _instance; \
    } \
    - (NSUInteger)retainCount \
    { \
    return  MAXFLOAT; \
    }
    #endif
    
    
    • Person.h类
    #import <Foundation/Foundation.h>
    #import "Singleton.h"
    
    @interface Person : NSObject
    
    interfaceSingleton(Person);
    
    @end
    
    
    
    #import "Person.h"
    
    @implementation Person
    
    
    implementationSingleton(Person)
    
    @end
    

    相关文章

      网友评论

          本文标题:第六章、oc的语言高级阶段

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