iOS开发总结之 Foundation框架总结

19 篇文章 0 订阅

一.字符串

1.创建nsstring基本方式

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    //如何创建字符串对象
    /*
     通过不同的方式创建字符串,字符串对象储存的位置也不一样
     >如果是通过字符串常量创建,那么字符串对象存储在常量区中
     >如果是通过alloc initWithFormat/stringWithFormat创建,那么字符串对象存储在堆区中
     而且需要注意:
     >不同的平台存储的方式也不一样,如果是Mac平台系统会自动对字符串对象进行优化,但是如果是iOS平台就是两个对象
     >不同的编译器存储的方式也不一样,如果是Xcode6以下并且是在iOS平台,那么每次alloc都会创建一个新的对象,如果是在Xcode6以上那么alloc多次指向同一块存储空间
     
     */
    
    //1.通过字符串常量创建
    //注意:如果是通过字符串常量创建对象,并且字符串常量的内容一致,那么如果创建多个字符串对象,多个对象指向同一块存储空间
    NSString *str1 = @"lnj";
    NSString *str11 = @"lnj";
    NSLog(@"str1 = %p, str11 = %p", str1 ,str11);
    
    //2.通过alloc init创建
    //只要调用alloc就会在堆内存中开辟一块存储空间
    NSString *str2 = [[NSString alloc]initWithFormat:@"lmj"];
    NSString *str22 = [[NSString alloc]initWithFormat:@"lmj"];
    NSLog(@"str2 = %p, str22 = %p", str2, str22);
    
    //3.通过类工厂方法创建/ stringWithFormat
    //内部其实就是封装了alloc init
    NSString *str3 = [NSString stringWithFormat:@"zs"];
    NSString *str33= [NSString stringWithFormat:@"zs"];
    
    /*
     注意:一般情况下,只要是通过alloc或者类工厂方法创建的对象,每次都会在堆内存中开辟一块新的存储空间
     但是如果是通过alloc的initWithString方法除外,因为这个方法是通过copy返回一个字符串对象给我们
     而copy又分为深拷贝和浅拷贝,如果是深拷贝会创建一个新的对象,如果是浅拷贝不会创建一个新的对象,而是直接返回被拷贝的对象的地址给我们
     */
    
    NSString *str4 = [[NSString alloc]initWithString:@"ls"];
    NSString *str44 = [[NSString alloc]initWithString:@"ls"];
    NSLog(@"str4 = %p, str44 = %p", str4, str44);

    return 0;
}

2.字符串读写

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    /*
     file: 文件路径,
     encoding: 编码英文 iOS-5988-1 中文 GBK GBK2312 , 一般情况填写UTF-8
     error: 如果读取错误, 会将错误信息保存到error中 ,如果读取正确, 就没有error = nil
     注意: 以后在OC方法中但凡看到XXXofFile的方法, 传递的一定是全路径(绝对路径)
     */
    NSString *path = @"/Users/xxx/Desktop/n2186/day17/note/abc.txt";
    NSError *error = nil;
    
    // 从文件中读取字符串
    
    NSString *str = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
    if (error == nil) {
        
        NSLog(@"str = %@", str);
    }else
    {
//        error.code;
//        error.description;
        NSLog(@"error = %@", [error localizedDescription]);
    }
   
    
    /*
     
    // 将字符串写入到文件中
    NSString *str = @"iOS0601";
    // atomically 如果传入YES, 字符串写入文件的过程中如果没有写完, 那么不会生成文件
    //            如果传入NO, 字符串写入文件的过程中如果没有写完, 会生成文件
    NSString *path2 = @"/Users/xxx/Desktop/abc.txt";
    BOOL flag = [str writeToFile:path2 atomically:YES encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"flag = %i", flag);
     */
    
    
    return 0;
}

3.文件读写、url编码

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
  
    //1.文件读取
    /*
     //1.创建URL
     //协议头 + 主机地址 + 文件路径
     //    NSString *path = @"file://192.168.199.199/Users/xxx/Desktop/abc.txt";
     //    NSString *path = @"http://www.baidu.com";
     
     //注意:如果加载的资源是本机上的资源,那么URL中的主机地址可以省略
     //虽然主机地址可以省略,但是需要注意,文件路劲中最前面的/不能省略,文件路径最前面的/代表根路径
     //    NSString *path = @"file:///Users/xxx/Desktop/abc.txt";
     //    NSURL *url = [NSURL URLWithString:path];
     
     //    NSString *path = @"file:///Users/xxx/Desktop/";
     //注意:如果是通过NSURL的fileURLWithPath:方法创建URL,那么系统会自动给我们传入的字符串添加协议头(file://),所以字符串中不需要再写file://
     //    注意:开发中一 般情况下,如果是访问本机的资源,创建URL的时候,建议使用fileURLWithPath方法创建
     //因为url不支持中文,如果URL中包含中文,那么无法访问;但是如果是通过fileURLWithString方法创建URL,哪怕URL中包含中文也可以进行访问,系统内部会自动对URL中包含的中文进行处理
     //    NSURL *url = [NSURL fileURLWithPath:path];
     
     NSString *path = @"file:///Users/xxx/Desktop/未命名文件夹/abc.txt";
     //如果URL中包含中文,又非不通过fileURLWithPath创建,也可以破
     //如果想破就必须在创建URL之前先对字符串中的中文进行处理,进行百分号编码
     NSLog(@"处理前:%@", path);
     path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
     NSLog(@"处理后:%@", path);
     
     NSURL *url = [NSURL URLWithString:path];
     NSLog(@"url = %@", url);
     
     //2.根据URL加载文件中的字符串
     NSString *str = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
     
     NSLog(@"str = %@", str);
     
     */
    
    //2.文件写入
    NSString *str = @"abc";
    //    NSString *path = @"file:///Users/xxx/Desktop/未命名文件夹/abc.txt";
    //    path = [path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    //    NSURL *url = [NSURL URLWithString:path];
    
    NSString *path = @"/Users/xxx/Desktop/未命名文件夹/abc.txt";
    NSURL *url = [NSURL fileURLWithPath:path];
    [str writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
    
    //注意点:如果多次往同一个文件中写入内容,那么后一次的会覆盖前一次的
    NSString *str2 = @"xxoo";
    [str2 writeToURL:url atomically:YES encoding:NSUTF8StringEncoding error:nil];
    

    
    return 0;
}

4.字符串比较

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    NSString *str1 = @"abc";
    NSString *str2 = @"ABC";
    
    /*
    // 比较两个字符串的"内容"是否相同
    BOOL flag = [str1 isEqualToString:str2];
    NSLog(@"flag = %i", flag);
    
    // 下面这个方法, 是比较两个字符串的"地址"是否相同
    flag = (str1 == str2);
    NSLog(@"flag = %i", flag);
     */
    
    // 比较字符串的大小
    
    // NSOrderedAscending  前面的小于后面的
    // NSOrderedSame,  两个字符串相等
    // NSOrderedDescending  前面的大于后面的
    switch ([str1 compare:str2]) {
        case NSOrderedAscending:
            NSLog(@"str1小于str2");
            break;
        case NSOrderedSame:
            NSLog(@"str1等于str2");
            break;
        case NSOrderedDescending:
            NSLog(@"str1大于str2");
            break;
        default:
            break;
    }
    
    
    /*
    // 忽略大小写进行比较
    switch ([str1 caseInsensitiveCompare:str2]) {
        case NSOrderedAscending:
            NSLog(@"str1小于str2");
            break;
        case NSOrderedSame:
            NSLog(@"str1等于str2");
            break;
        case NSOrderedDescending:
            NSLog(@"str1大于str2");
            break;
        default:
            break;
    }
     */
    return 0;
}

5.字符串搜索

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

//    NSString *str = @"http://www.cocochina.com;
    // 1.判断是否以什么开头
    /*
    // 本质就是从字符串的第一个字符开始匹配, 只要不匹配就返回NO
    if ([str hasPrefix:@"http://"]) {
        NSLog(@"是一个URL");
    }else
    {
        NSLog(@"不是一个URL");
    }
     */
    
    // 2.判断是否以什么结尾
    /*
    // 本质就是从字符串的最后一个字符开始匹配, 只要不匹配就返回NO
    if ([str hasSuffix:@".gif"]) {
        NSLog(@"动态图片");
    }else{
        NSLog(@"不是动态图片");
    }
     */
    
    // 3.判断字符串中是否包含某一字符串
    /*
    NSString *str = @"abcd";
    // 只要str中包含该字符串, 那么就会返回该字符串在str中的起始位置以及该字符串的长度
    // location从0开始 , length从1开始
    // 如果str中没有需要查找的字符串, 那么返回的range的length=0, location = NSNotFound
    NSRange range =  [str rangeOfString:@"lnj"];
//    if (range.location == NSNotFound) {
    if (range.length == 0){
        NSLog(@"str中没有需要查找的字符串");
    }else{
        NSLog(@"str中有需要查找的字符串");
        NSLog(@"location = %lu, length = %lu", range.location, range.length);
    }
     */
    return 0;
}

6.字符串截取

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    NSString *str = @"<head>小码哥</head>";
    /*
    // NSRange : 位置/长度
//    NSRange range = {6, 3};
//    NSRange range;
//    range.location = 6;
//    range.length = 3;
    // 只要是OC提供的结构体, 一般都可以使用NSMakeXXX来创建
//    NSRange range = NSMakeRange(6, 3);
    */
    /*
    // 1.动态获取截取的起始位置
    NSUInteger location = [str rangeOfString:@">"].location + 1;
    // 2.动态获取截取的长度
    // 注意:rangeOfString是从左至右的开始查找, 只要找到就不找了
//    NSUInteger length = [str rangeOfString:@"<" options:NSBackwardsSearch].location - location;
    NSUInteger length = [str rangeOfString:@"</"].location - location;
    NSLog(@"location = %lu, length = %lu", location, length);
    NSRange range = NSMakeRange(location, length);
    NSString *newStr = [str substringWithRange:range];
    NSLog(@"str = %@", str);
    NSLog(@"newStr = %@", newStr);
   
    
//    NSString *temp = @"abcdefa";
//    NSRange range =[temp rangeOfString:@"a" options:NSBackwardsSearch];
//    NSLog(@"%lu", range.location);
     */
    
    // 从什么地方开始截取, 一直截取到最后
//    NSString *newStr = [str substringFromIndex:6];
//    NSLog(@"newStr = %@", newStr);
    // 从开头开始截取, 一直截取到什么位置
//    NSString *newStr = [str substringToIndex:6];
//    NSLog(@"newStr = %@", newStr);
    
    /*
     <head>小码哥</head> --> 小码哥</head>  --> 小码哥
     <head>小码哥</head> --> <head>小码哥  --> 小码哥
    */
    NSLog(@"str = %@", str);
    NSUInteger location = [str rangeOfString:@">"].location + 1;
    NSString *newStr = [str substringFromIndex:location];
    NSLog(@"newStr = %@", newStr);
    
    location = [newStr rangeOfString:@"</"].location;
    // 改变了指针的指向, 并不是修改了原来的字符串
    newStr = [newStr substringToIndex:location];
    NSLog(@"newStr = %@", newStr);
    
    return 0;
}

7.字符串替换

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
   
    // 需求: 将&符号替换为/
    NSString *str = @"http:&&www.baidu.com&img&ht.gif";
    
    // OccurrencesOfString: 要替换谁
    // withString: 用谁替换
    NSString *newStr = [str stringByReplacingOccurrencesOfString:@"&" withString:@"/"];
    NSLog(@"newStr = %@", newStr);
    
    
    /*
    // 1.去除空格  2.将&替换为/
    NSString *str = @"   http:   &&www.   baidu.com   &img&ht.gif   ";
    // 1.去除空格
    NSString *newStr = [str stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"newStr = |%@|", newStr);
    NSString *newStr2 = [newStr stringByReplacingOccurrencesOfString:@"&" withString:@"/"];
    NSLog(@"newStr2 = |%@|", newStr2);
     */
    /**
    // 3.替换首尾
    
//    NSString *str = @"   http:&&www.baidu.com&img&ht.gif   ";
    NSString *str = @"HTTP://www.baidu.com&img&ht.gif";
//    NSCharacterSet *set = [NSCharacterSet whitespaceCharacterSet];
//    NSString *newStr = [str stringByTrimmingCharactersInSet:set];
    NSCharacterSet *set = [NSCharacterSet uppercaseLetterCharacterSet];
    NSString *newStr = [str stringByTrimmingCharactersInSet:set];
    NSLog(@"newStr = |%@|", newStr);
    */
    
    return 0;
}

8.字符串与路径

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    NSString *str = @"User/ht/Desktop/abc.txt.jpg";
    // 1.判断是否是绝对路径
    /*
    // 其实本质就是判断字符串是否以/开头
    if([str isAbsolutePath])
    {
        NSLog(@"是绝对路径");
    }else{
        NSLog(@"不是绝对路径");
    }
     */
    
    // 2.获取文件路径中的最后一个目录
    // 本质就是获取路径中最后一个/后面的内容
    /*
    NSString *newStr = [str lastPathComponent];
    NSLog(@"%@", newStr);
     */
    
    // 3.删除文件路径中的最后一个目录
    /*
    // 本质就是删除最后一个/后面的内容, 包括/也会被删除
    NSString *newStr = [str stringByDeletingLastPathComponent];
    NSLog(@"%@", newStr);
     */
    
    // 4.给文件路径添加一个目录
    /*
     // 本质就是在字符串的末尾加上一个/ 和指定的内容
     // 注意: 如果路径后面已经有了/, 那么就不会添加了
     //      如果路径后面有多个/, 那么会自动删除多余的/, 只保留一个
     NSString *newStr = [str stringByAppendingPathComponent:@"png"];
     NSLog(@"%@", newStr);
     */
    
    // 5.获取路径中文件的扩展名
    /*
    // 本质就是从字符串的末尾开始查找., 截取第一个.后面的内容
    NSString *newStr = [str pathExtension];
    NSLog(@"%@", newStr);
     */
    
    // 6.删除路径中文件的扩展名
    /*
    // 本质就是从字符串的末尾开始查找.,删除第一个.和.后面的内容
    NSString *newStr = [str stringByDeletingPathExtension];
    NSLog(@"%@", newStr);
     */
    
    // 7.给文件路径添加一个扩展名
    // 本质就是在字符串的末尾加上一个.和指定的内容
    NSString *newStr = [str stringByAppendingPathExtension:@"jpg"];
    NSLog(@"%@", newStr);
    
    return 0;
}

9.字符串转换

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

//    NSString *str = @"abc";
    
    // 1.将字符串转换为大写
    /*
    NSString *newStr = [str uppercaseString];
    NSLog(@"%@", newStr);
    */
    // 2.将字符串转换为小写
    /*
    NSString *newStr2 = [newStr lowercaseString];
    NSLog(@"%@", newStr2);
    
//    htpp://www.baidu.com/img/abc.GIF;
    */
    
    // 3.将字符串的首字符转换为大写
    /*
    NSString *newStr = [str capitalizedString];
    NSLog(@"%@", newStr);
     */
    
    // 4.字符串与基本数据类型的转换
    /*
    NSString *str1 = @"110";
    NSString *str2 = @"120";
//    str1 + str2; // 错误
    int value1 = [str1 intValue];
    int value2 = [str2 intValue];
    NSLog(@"sum = %i", value1 + value2);
    
    // 注意: 如果不是int,double,float,bool,integer,longlong这些类型就不要乱用
    NSString *str3 = @"abc";
    int value3 = [str3 intValue];
    NSLog(@"value3 = %i", value3);
     */
    
    // 5.C语言字符串和OC字符串之间的转换
    /*
    char *cStr = "abc";
    NSString *str = [NSString stringWithUTF8String:cStr];
    NSLog(@"str = %@", str);
    
    NSString *newStr = @"cdf";
    const char *cStr2 = [newStr UTF8String];
    NSLog(@"cStr2 = %s", cStr2);
     
     */
    return 0;
}

10.NSMutableString

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    
    /*
    NSString *str = @"abc"; // 一开始str指向@"abc"对应的内存
    str = @"cde"; // 修改了str指针的指向, 让它指向@"cde"对应的内存
    NSString *newStr = [str stringByReplacingOccurrencesOfString:@"c" withString:@"X"];
    NSLog(@"%@", newStr);
    */
    
    // 创建一个空的字符串
    NSMutableString *str = [NSMutableString string];
    NSLog(@"修改前: %@", str);
    [str appendString:@"lnj"];
    NSLog(@"修改后: %@", str);
    
    NSMutableString *strM = [[NSMutableString alloc] init];
//    strM = [NSMutableString alloc] initWithFormat:<#(NSString *), ...#>
//    strM = [NSMutableString stringWithFormat:<#(NSString *), ...#>]
    
    return 0;
}

11.NSMutableString常用方法

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    NSMutableString *strM = [NSMutableString stringWithFormat:@"www.baidu.com.388"];
    
    // 1.在字符串后面添加/image
    /*
    [strM appendString:@"/image"];
//    [strM appendFormat:@"/age is %i", 10];
    NSLog(@"strM = %@", strM);
    */
    // 2.删除字符串中的388
    /*
    // 技巧: 在开发中, 我们经常利用rangeOfString和deleteCharactersInRange方法配合起来删除指定的字符串
    // 2.1先查找出388在字符串中的位置
    NSRange range = [strM rangeOfString:@"388"];
    // 2.2删除388
    [strM deleteCharactersInRange:range];
    NSLog(@"strM = %@", strM);
     */
    
    // 3.在388前面插入love这个单词
    /*
    // insertString : 需要插入的字符串
    // atIndex: 从哪里开始插入
    NSRange range = [strM rangeOfString:@"388"];
    [strM insertString:@"love" atIndex:range.location];
    NSLog(@"strM = %@", strM);
     */
    
    // 4.要求将字符串中的388替换为530
    // 注意: 如果是调用NSString的字符串替换方法, 不会修改原有字符串, 而是生成一个新的字符串
//    NSString *newStr =[strM stringByReplacingOccurrencesOfString:@"388" withString:@"530"];
    
    // 注意: 一般情况下OC方法要求传入一个参数如果没有*, 大部分都是枚举
    //      一般情况下如果不想使用枚举的值, 可以传入0, 代表按照系统默认的方式处理
    // OccurrencesOfString: 需要替换的字符串
    // withString: 用什么替换
    // options: 替换时的搜索方式
    // range: 搜索的范围
    // 返回值: 代表替换了多少个字符串
    NSUInteger count = [strM replaceOccurrencesOfString:@"388" withString:@"530" options:0 range:NSMakeRange(0, strM.length)];
    NSLog(@"strM = %@", strM);
    NSLog(@"count = %lu", count);
    
//    NSLog(@"newStr = %@", newStr);
    
    return 0;
}

二、数组

1.nsarray

NSArray
#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {

    /*
//    NSArray *arr = [[NSArray alloc] init];
//    NSArray *arr = [NSArray arrayWithObject:@"a"];
    // 数组中的nil是结束符
    NSArray *arr = [NSArray arrayWithObjects:@"la", @"lb" ,@"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:@"la", @"lb", @"jjj", @"zs", nil];
    if([arr containsObject:@"zs"])
    {
        NSLog(@"arr中包含zs");
    }else
    {
        NSLog(@"arr中不包含zs");
    }
     */
    
    // 创建数组简写
    NSString *str = @"la";
//    NSArray *arr = [NSArray arrayWithObjects:@"laj", @"lbj", @"jjj", nil];
    NSArray *arr = @[@"aj", @"lbj", @"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 = @[@"a", @"la", @"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;
}

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.nsstring和nsarray之间转换

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

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

5.nsarray读写

#import <Foundation/Foundation.h>
#import "Person.h"

int main(int argc, const char * argv[]) {
    // 1.将数组写入到文件中
    /*
    NSArray *arr = @[@"l", @"j", @"jjj"];
    // 其实如果将一个数组写入到文件中之后, 本质是写入了一个XML文件
    // 在iOS开发中一般情况下我们会将XML文件的扩展名保存为plist
    BOOL flag = [arr writeToFile:@"/Users/qinlong/Downloads/已经归档分类的/公司项目/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/qinlong/Downloads/已经归档分类的/公司项目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:@[@"l", @"jjj"]];
    // 注意: 以下是将整个数组作为一个元素添加
//    [arrM addObject:@[@"l", @"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);
    /*
    // 如何删除
    [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 = @[@"l", @"j"];
    [arrM addObject:@"JJJ"];*/
    
    return 0;
}

三.字典

1.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:@[@"l", @"300", @"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":@"l", @"age":@"300", @"height":@"1.75"};
//    NSLog(@"%@ %@ %@", dict[@"name"], dict[@"age"], dict[@"height"]);
    
    // 2.字典的遍历
//    NSDictionary *dict = @{@"name":@"l", @"age":@"300", @"height":@"1.75"};
    // 2.1如何获取字典中key和value的个数, 在字典中key称之为键, value称之为值
//    NSLog(@"count = %lu", [dict 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":@"l", @"age":@"300", @"height":@"1.75"};
    // XML 扩展名plist
    [dict writeToFile:@"/Users/qinlong/Downloads/已经归档分类的/公司项目/info.plist" atomically:YES];
    
    // 注意: 字典和数组不同, 字典中保存的数据是无序的
    NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:@"/Users/xiaomage/Desktop/info.plist"];
    NSLog(@"%@", newDict);
    
    
    NSArray *arr = @[@10, @20, @30, @5];
    [arr writeToFile:@"/Users/qinlong/Downloads/已经归档分类的/公司项目/abc.plist" atomically:YES];
    
    return 0;
}

2.nsmutabledictionary

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    /*
    // 1.创建一个空的字典
    NSMutableDictionary *dictM = [NSMutableDictionary  dictionary];
    NSLog(@"%@", dictM);
    // 2.如何添加
    [dictM setObject:@"l" forKey:@"name"];
    NSLog(@"%@", dictM);
    // 会将传入字典中所有的键值对取出来添加到dictM中
    [dictM setValuesForKeysWithDictionary:@{@"age":@"300", @"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":@"l"};
//    [dictM setObject:@"30" forKey:@"age"];
    
    
    // 2.如果是不可变数组, 那么key不能相同
    // 如果是不可变字典出现了同名的key, 那么后面的key对应的值不会被保存
    // 如果是在可变数组中, 后面的会覆盖前面的
    NSDictionary *dict = @{@"name":@"l", @"name":@"j"};
    NSLog(@"dict = %@", dict);
    
    NSMutableDictionary *dictM = [NSMutableDictionary dictionaryWithObjects:@[@"lj", @"j"] forKeys:@[@"name", @"name"]];
    NSLog(@"dict = %@", dictM);
    
    return 0;
}

四.nsnumber

#import <Foundation/Foundation.h>

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;
}
<h2>五.nsvalue</h2>
</pre><pre code_snippet_id="1702228" snippet_file_name="blog_20160604_21_9228691" name="code" class="objc">
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    /*
    typedef struct{
        int age;
        char *name;
        double _height;
    }Person;
    
    Person p = {300, "l", 1.75};
//    NSArray *arr = @[p];
     */
    
    // 1.利用NSValue包装常用的结构体
    /*
    CGPoint point = NSMakePoint(10, 20);
    NSValue *value = [NSValue valueWithPoint:point];
    NSArray *arr = @[value];
    NSLog(@"%@", arr);
     */
    
    // 2.利用NSValue包装自定义的结构体
    typedef struct{
        int age;
        char *name;
        double height;
    }Person;
    
    Person p = {300, "j", 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;
}

六.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);
     */

    // 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);
    
    return 0;
}

七.NSFileManager

#import <Foundation/Foundation.h>

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


八.copy

1.基本使用

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    /*
     // 会生成一个新的对象
    NSString *srcStr = @"abc";
    // 只要是拷贝出来的对象, 拷贝出来的对象中的内容和以前对象中的内容一致
    // "一般"情况下拷贝会生成一个新的对象
    // 为什么会产生一个新的对象 1.因为拷贝要求修改原来的对象不能影响到拷贝出来得对象 \
                              修改拷贝出来的对象也不能影响到原来的对象, 所以需要生成一个新的对象 \
                            2.由于以前的对象是一个不可变的对象, 而通过mutableCopy拷贝出来的对象必须是一个可变的对象, 所以必须生成一个新的对象
    
    NSMutableString *copyStr = [srcStr mutableCopy];
    NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
    NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
     
     */
    
    /*
     //  会生成一个新的对象
    NSMutableString *srcStr = [NSMutableString stringWithFormat:@"labc"];
    NSMutableString *copyStr = [srcStr mutableCopy];
    
    [srcStr appendString:@" cool"];
    NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
    NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
     */
    

     //  会生成一个新的对象
    /**
    NSMutableString *srcStr = [NSMutableString stringWithFormat:@"abc"];
    NSString *copyStr = [srcStr copy];
    [srcStr appendString:@" cool"];
    NSLog(@"srcStr = %@, copyStr = %@", srcStr, copyStr);
    NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
   */
    
    //不会生成新对象
    
    // 如果是通过不可变对象调用了copy方法, 那么不会生成一个新的对象
    // 原因: 因为原来的对象是不能修改的, 拷贝出来的对象也是不能修改的
    // 既然两个都不能修改, 所以永远不能影响到另外一个对象, 那么已经符合需求
    // 所以: OC为了对内存进行优化, 就不会生成一个新的对象
    /**
    NSString *srcStr = @"lccj";
    NSString *copyStr = [srcStr copy];
    NSLog(@"srcStr = %p, copyStr = %p", srcStr, copyStr);
    */
    /*
     正是因为调用copy方法有时候会生成一个新的对象, 有时候不会生成一个新的对象
     所以: 如果没有生成新的对象, 我们称之为浅拷贝, 本质就是指针拷贝
          如果生成了新的对象, 我们称之为深拷贝, 本质就是会创建一个新的对象
     */
    return 0;
}

2.内存管理

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {

    @autoreleasepool {
#pragma mark 在MRC环境下内存管理
        /*
        //NSString *str1 = @"abc";
        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;
}

3.Copy与Property

 

#import <Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"

int main(int argc, const char * argv[]) {

    
    // 1.copy的第一个用途, 防止外界修改对象内部的数据
    
    /*
    NSMutableString *temp = [NSMutableString stringWithFormat:@"sbc"];
    
    Person *p = [[Person alloc] init];
    p.name = temp; //把temp指针赋值给了name  (此时 temp 和 name 都指向同一块内存空间)
    
    // 问题: 修改了外面的变量, 影响到了对象中的属性
    [temp appendString:@" cool"];
    
    NSLog(@"name = %@", p.name);  //打印结果: sbc cool
    
    // 记住: 以后字符串属性都用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;
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值