NSFileManger的介绍和用法(文件操作)
1、NSFileManager的介绍
NSFileManager:用来管理文件系统的,进行常见的文件或文件夹操作(拷贝、剪切、创建等)
NSFileManager使用了单例模式singleton,使用defaultManager方法可以获得那个单例对象
2、NSFileManager的基本使用(常见的判断)
NSString
*filePath =
@"/Users/ZacharyUE/Desktop/str.plist
”
;//先给一个路径
NSString *filePath2 = @"/Users/ZacharyUE/Desktop" ;
//NSFileManager 用于判断
// 创建文件管理对象,单例对象(在程序运行期间,只有一个对象存在)
NSFileManager *fm = [ NSFileManager defaultManager ];
//1 )判断文件是否存在
BOOL isYES = [fm fileExistsAtPath :filePath];
NSLog ( @"%d" , isYES);
//2 )判断是否是一个目录
if (isYES) {
BOOL isDir;
[fm fileExistsAtPath :filePath2 isDirectory :&isDir];
if (isDir) {
NSLog ( @" 这是一个目录 " );
} else {
NSLog ( @" 不是一个目录 " );
}
}
//3 )判断文件是否可读
isYES = [fm isReadableFileAtPath :filePath];
NSLog ( @"%d" , isYES);
//4 )是否可写
isYES = [fm isWritableFileAtPath :filePath2];
NSLog ( @"%d" , isYES);
//5 )是否可删除
isYES = [fm isDeletableFileAtPath :filePath];
NSString *filePath2 = @"/Users/ZacharyUE/Desktop" ;
//NSFileManager 用于判断
// 创建文件管理对象,单例对象(在程序运行期间,只有一个对象存在)
NSFileManager *fm = [ NSFileManager defaultManager ];
//1 )判断文件是否存在
BOOL isYES = [fm fileExistsAtPath :filePath];
NSLog ( @"%d" , isYES);
//2 )判断是否是一个目录
if (isYES) {
BOOL isDir;
[fm fileExistsAtPath :filePath2 isDirectory :&isDir];
if (isDir) {
NSLog ( @" 这是一个目录 " );
} else {
NSLog ( @" 不是一个目录 " );
}
}
//3 )判断文件是否可读
isYES = [fm isReadableFileAtPath :filePath];
NSLog ( @"%d" , isYES);
//4 )是否可写
isYES = [fm isWritableFileAtPath :filePath2];
NSLog ( @"%d" , isYES);
//5 )是否可删除
isYES = [fm isDeletableFileAtPath :filePath];
NSLog(@"%d", isYES);
3、NSFileManager用法深入1
-
NSFileManager的文件访问
//
创建文件对象
NSFileManager *fm = [NSFileManager defaultManager];
NSString
*filePath =
@"/Users/ZacharyUE/Desktop/str.plist
”
; //文件路径
NSString *dirPath = @"/Users/ZacharyUE/Desktop/儒释道”; //目录路径
//1
)何如获取文件的信息(属性)
NSDictionary *dic = [fm attributesOfItemAtPath :filePath error : nil ];
NSLog ( @"%@" , dic);
NSLog ( @"%@, %@" , [dic objectForKey : @"NSFileOwnerAccountName" ], dic[ @"NSFileOwnerAccountName" ]); // 字典通过 key 获取值,两种方式
//2 )获取指定目录下文件及子目录
// 使用递归的方式 获取当前目录及子目录下的所有文件及文件夹
NSArray *arr = [fm subpathsAtPath :dirPath];
// 这种方法不是使用递归的方式实现
arr = [fm subpathsOfDirectoryAtPath :dirPath error : nil ];
NSLog ( @"%@" , arr);
//3 )获取指定目录下的子目录(不在获取后代路径 , 即不在获取子目录下的信息)
arr = [fm contentsOfDirectoryAtPath :dirPath error : nil ];
NSDictionary *dic = [fm attributesOfItemAtPath :filePath error : nil ];
NSLog ( @"%@" , dic);
NSLog ( @"%@, %@" , [dic objectForKey : @"NSFileOwnerAccountName" ], dic[ @"NSFileOwnerAccountName" ]); // 字典通过 key 获取值,两种方式
//2 )获取指定目录下文件及子目录
// 使用递归的方式 获取当前目录及子目录下的所有文件及文件夹
NSArray *arr = [fm subpathsAtPath :dirPath];
// 这种方法不是使用递归的方式实现
arr = [fm subpathsOfDirectoryAtPath :dirPath error : nil ];
NSLog ( @"%@" , arr);
//3 )获取指定目录下的子目录(不在获取后代路径 , 即不在获取子目录下的信息)
arr = [fm contentsOfDirectoryAtPath :dirPath error : nil ];
NSLog(@"%@", arr);
4、NSFileManager用法深入2
//
第一步,必须有文件管理对象
NSFileManager *fm = [ NSFileManager defaultManager ];
NSFileManager *fm = [ NSFileManager defaultManager ];
//如何创建目录(路径:/Users/ZacharyUE/Desktop/dir)
NSString
*createDirPath =
@"/Users/ZacharyUE/Desktop/dir"
;
/*
createDirectoryAtPath:@" 路径 " withIntermediateDirectories:YES/NO
YES/NO: 会把缺失文件夹补上来,后者如果上级文件夹确实,会报错
attributes: 属性的字典 error: 错误对象
*/
BOOL isYES = [fm createDirectoryAtPath :createDirPath withIntermediateDirectories : NO attributes : nil error : nil ];
if (isYES) {
NSLog ( @"%d" , isYES);
/*
createDirectoryAtPath:@" 路径 " withIntermediateDirectories:YES/NO
YES/NO: 会把缺失文件夹补上来,后者如果上级文件夹确实,会报错
attributes: 属性的字典 error: 错误对象
*/
BOOL isYES = [fm createDirectoryAtPath :createDirPath withIntermediateDirectories : NO attributes : nil error : nil ];
if (isYES) {
NSLog ( @"%d" , isYES);
}
//
如何创建文件
NSString *str = @"我shi最棒的!";//写入到@"/Users/ZacharyUE/Desktop/dir/me.txt";
//以下的
createDirPath =
@"/Users/ZacharyUE/Desktop/dir
/me.txt
"
;
//1
)
writeToFile
//2 ) createFileAtPath
/*
createFileAtPath:@" 路径 " contents:NSData 类型的数据 attributes: 文件的属性的字典
创建 NSData :是一个处理二进制数据的类
将 NSString-------- 》 NSData
*/
NSData *data = [str dataUsingEncoding : NSUTF8StringEncoding ];
BOOL isYES = [fm createFileAtPath :createDirPath contents :data attributes : nil ];
//2 ) createFileAtPath
/*
createFileAtPath:@" 路径 " contents:NSData 类型的数据 attributes: 文件的属性的字典
创建 NSData :是一个处理二进制数据的类
将 NSString-------- 》 NSData
*/
NSData *data = [str dataUsingEncoding : NSUTF8StringEncoding ];
BOOL isYES = [fm createFileAtPath :createDirPath contents :data attributes : nil ];
NSLog(@"%d", isYES);
//
如何
copy
文件
NSString *copyPath = @"/Users/ZacharyUE/Desktop/dir/xxx/me.txt" ;
BOOL isYES = [fm copyItemAtPath :createDirPath toPath :copyPath error : nil ];
NSString *copyPath = @"/Users/ZacharyUE/Desktop/dir/xxx/me.txt" ;
BOOL isYES = [fm copyItemAtPath :createDirPath toPath :copyPath error : nil ];
NSLog(@"%d", isYES);
//
如何移动文件
NSString *movePath = @"/Users/ZacharyUE/Desktop/dir/aaa/me.txt" ;
NSString *movePath = @"/Users/ZacharyUE/Desktop/dir/aaa/me.txt" ;
[fm moveItemAtPath:createDirPath toPath:movePath error:nil];
//
如何删除文件,
@"/Users/ZacharyUE/Desktop/dir/me.txt"
[fm removeItemAtPath:createDirPath error:nil];
5、NSFileManager文件下载的思路
1)发送请求给服务器,要求下载某个文件
2)服务器发出响应,返回文件数据
3)手机客户端利用NSData来存放服务器返回的文件数据
4)利用NSFileManager将NSData里面的文件数据写到新的文件中
6、iOS沙盒(sandbox)机制
每个iOS应用都有自己的应用沙盒,应用沙盒就是文件系统目录,与其他应用的文件系统隔离,iOS系统不允许访问其他应用的应用沙盒。
在iOS8中已经开放访问(extension),对几个固定系统区域的扩展机制。
应用沙盒一般包含几个文件目录:应用程序包、Documents、Libaray(子目录Caches和Preferences)、tmp
应用程序包:包含所有的资源文件和可执行文件。
Documents:保存应用运行时生成的需要持久化的数据,iTunes会自动备份该目录。
tmp:保存应用运行时所需的零时数据,使用完后相应地文件从该目录删除。未运行时,系统也可能清除该目录的文件,iTunes不会同步该目录。iPhone重启时,该目录下的文件会丢失。
Libaray:存储程序的默认设置和其它状态信息,iTunes会自动备份该目录。
Libaray/Caches:存储缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出时删除。
Libaray/Preference:保存应用的所有偏好设置(配置信息\SQLite),iOS的Settings(设置)应用会在该目录中查找应用的设置信息,iTunes会自动备份该目录。
//
沙盒路径获取方法:
//1 )沙盒的路径
NSString *sandBoxPath = NSHomeDirectory ();
NSLog ( @"sandBoxPath = %@" , sandBoxPath); // 在 Mac 下,用户根目录
//2 ) tmp 路径
NSString *tmpPath = NSTemporaryDirectory ();
NSLog ( @"tmpPath = %@" , tmpPath);
//2 ) Documents 路径
// NSSearchPathForDirectoriesInDomains( 要查找的目录 , 是否使用主目录 , YES/NO 是否获取全路径 )
NSArray *arr = NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES );
NSLog ( @"%@" , arr);
//4 ) Library 、 caches 同理
arr = NSSearchPathForDirectoriesInDomains ( NSLibraryDirectory , NSUserDomainMask , YES );
NSLog ( @"%@" , arr);
//5 ) preferences 路径,在 Libaray 的基础上,拼接 /Preferences
//1 )沙盒的路径
NSString *sandBoxPath = NSHomeDirectory ();
NSLog ( @"sandBoxPath = %@" , sandBoxPath); // 在 Mac 下,用户根目录
//2 ) tmp 路径
NSString *tmpPath = NSTemporaryDirectory ();
NSLog ( @"tmpPath = %@" , tmpPath);
//2 ) Documents 路径
// NSSearchPathForDirectoriesInDomains( 要查找的目录 , 是否使用主目录 , YES/NO 是否获取全路径 )
NSArray *arr = NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES );
NSLog ( @"%@" , arr);
//4 ) Library 、 caches 同理
arr = NSSearchPathForDirectoriesInDomains ( NSLibraryDirectory , NSUserDomainMask , YES );
NSLog ( @"%@" , arr);
//5 ) preferences 路径,在 Libaray 的基础上,拼接 /Preferences
NSString *filePath = [arr lastObject];
//
stringByAppendingPathComponent用于拼接,也可以创建文件:
@“Preferences/a.txt"
NSString
*str = [filePath
stringByAppendingPathComponent
:
@"Preferences"
];
NSLog(@"%@", str);
7、常见的结构体
1)NSPoint和CGPoint的使用(点)
/* Points. */
//二维平面的一个点
struct
CGPoint {
CGFloat
x;
CGFloat
y;
};
typedef
struct
CGPoint
CGPoint;//
NSPoint是CGPoint的别名,没区别
CGPoint
c1;
//c1
是
CGPoint
结构体类型的变量
c1. x = 10 ;
c1. y = 10 ;
CGPoint c2 = { 10 , 10 };
//OC 特有的赋值
CGPoint c3 = CGPointMake ( 10 , 10 );
c1. x = 10 ;
c1. y = 10 ;
CGPoint c2 = { 10 , 10 };
//OC 特有的赋值
CGPoint c3 = CGPointMake ( 10 , 10 );
NSPoint c4 = NSMakePoint(5, 5);
2)NSSize和CGSize的使用(大小)
/* Sizes. */
//表示平面的面积
struct
CGSize {
CGFloat
width;//宽
CGFloat
height;//高
};
typedef
struct
CGSize
CGSize;
//同理,也有特有的赋值方式,形式与上面类似
CGSizeMake和
NSMake
Size
3)NSRect和CGRect的使用(矩形)
/* Rectangles. */
//表示从左上角某个点开始的矩形区域
struct
CGRect {
CGPoint
origin;//开始点
CGSize
size;//大小
};
typedef
struct
CGRect
CGRect;
CGRect
r1;
r1.origin.x = 0;
r1.
origin
.
y
=
0
;
r1.
size
.
width
=
200
;
r1.
size
.
height
=
80
;
CGRect
r2 = {{
0
,
0
}, {
10
,
20
}};
//OC
特有赋值方式
CGRect
r3 =
CGRectMake
(
0
,
0
,
30
,
80
);
NSRect r4 = NSMakeRect(0, 0, 89, 90);
//
快捷查看值的方法,转换为字符串
NSLog(@"r4 = %@", NSStringFromRect(r4));
//同理,上面的Size和Point都可以
4)常见结构体的使用注意
苹果官方推荐使用CG开头
8、NSNumber的使用
1)NSNumber的介绍和使用
OC中处理数字的一个类
NSArray和NSDictionary中只能存放OC对象,需要先将基本类型包装成对象,这样就可以存放到数组或字典
2)
NSNumber的创建
int
a =
10
;
NSNumber *intObj = [NSNumber numberWithInt:a];//其他类型同理
NSArray
*array = [
NSArray
arrayWithObjects
:intObj,
nil
];
NSLog(@"%@", array);
3)从
NSNumber对象中获取到基本数据类型
float
b =
2.3f
;
NSNumber *floatObj = [ NSNumber numberWithFloat :b];
[array addObject :floatObj];
NSLog ( @"%@" , array);
// 数组的第一个元素和第二个元素相加
//1 )取出数组的元素
//2 )把数组元素转换为基本数据类型
NSNumber *n1 = array[ 0 ];
int a1 = [n1 intValue ]; // 获取对象的整形值
NSNumber *n2 = array[ 1 ];
float b1 = [n2 floatValue ];
a1 = a1 + b1;
NSNumber *floatObj = [ NSNumber numberWithFloat :b];
[array addObject :floatObj];
NSLog ( @"%@" , array);
// 数组的第一个元素和第二个元素相加
//1 )取出数组的元素
//2 )把数组元素转换为基本数据类型
NSNumber *n1 = array[ 0 ];
int a1 = [n1 intValue ]; // 获取对象的整形值
NSNumber *n2 = array[ 1 ];
float b1 = [n2 floatValue ];
a1 = a1 + b1;
NSLog(@"%d", a1);
简写形式:@(变量名)、@数值或@YES,都是把变量、数值或YES包装成对象
9、NSValue的介绍和使用
NSNumber是NSValue的子类,
NSValue主要是把指针,CGRect结构体等包装成OC对象,以便存储。
(int/float/char/pointers/structures/object ids)
NSValue类的目标:允许以上数据类型的数据结构能够被添加到集合里,如NSArray和NSDictionary
为了方便结构体和
NSValue的转换,Foundation提供了一下方法:
1)存储结构体到集合
+ (
NSValue
*)valueWithPoint:(
NSPoint
)point;
+ (NSValue *)valueWithSize:(NSSize)size;
+ (NSValue *)valueWithRect:(NSRect)rect;
//
创建一个结构体变量,保存一个点
CGPoint p1 = CGPointMake ( 10 , 10 );
// 将结构体包装为 NSValue 对象
NSValue *pointObj = [ NSValue valueWithPoint :p1];
NSMutableArray *array = [ NSMutableArray arrayWithObjects :pointObj, nil ];
NSLog ( @"%@" , array);
// 创建一个结构体,保存 Size
CGSize s1 = CGSizeMake ( 20 , 20 );
NSValue *sizeObj = [ NSValue valueWithSize :s1];
[array addObject :sizeObj];
NSLog ( @"%@" , array);
// 创建一个结构体,保存 Rect
CGRect r1 = CGRectMake ( 1 , 1 , 22 , 33 );
[array addObject :[ NSValue valueWithRect :r1]];
CGPoint p1 = CGPointMake ( 10 , 10 );
// 将结构体包装为 NSValue 对象
NSValue *pointObj = [ NSValue valueWithPoint :p1];
NSMutableArray *array = [ NSMutableArray arrayWithObjects :pointObj, nil ];
NSLog ( @"%@" , array);
// 创建一个结构体,保存 Size
CGSize s1 = CGSizeMake ( 20 , 20 );
NSValue *sizeObj = [ NSValue valueWithSize :s1];
[array addObject :sizeObj];
NSLog ( @"%@" , array);
// 创建一个结构体,保存 Rect
CGRect r1 = CGRectMake ( 1 , 1 , 22 , 33 );
[array addObject :[ NSValue valueWithRect :r1]];
NSLog(@"%@", array);
2)从NSValue对象取出之前包装的结构体
- (NSPoint)pointValue;
- (NSSize)sizeValue;
- (NSRect)rectValue;
//
取最后的值
NSValue *lastValue = [array lastObject ];
NSRect r2 = [lastValue rectValue ];
NSValue *lastValue = [array lastObject ];
NSRect r2 = [lastValue rectValue ];
NSLog(@"%@", NSStringFromRect(r2));
//
转换为字符串
//
自定义结构体
typedef struct data {
int year;
int month;
int day;
typedef struct data {
int year;
int month;
int day;
} MYData;
//
定义结构体变量
MYData md = { 2015 , 9 , 3 };
// 将自定义结构体包装成 NSValue 对象
//@encode(MYData) 作用,把 MYData 类型生成一个常量字符串描述
NSValue *mdObj = [ NSValue valueWithBytes :&md objCType : @encode ( MYData )];
// 保存自定义结构体,到数组
NSMutableArray *arr = [ NSMutableArray arrayWithObjects :mdObj, nil ];
// 从数组取出 NSValue 对象
MYData md1;
MYData md = { 2015 , 9 , 3 };
// 将自定义结构体包装成 NSValue 对象
//@encode(MYData) 作用,把 MYData 类型生成一个常量字符串描述
NSValue *mdObj = [ NSValue valueWithBytes :&md objCType : @encode ( MYData )];
// 保存自定义结构体,到数组
NSMutableArray *arr = [ NSMutableArray arrayWithObjects :mdObj, nil ];
// 从数组取出 NSValue 对象
MYData md1;
[[arr
objectAtIndex
:
0
]
getValue
:&md1];
//getValue
获取的值,保存到
md1
中
//
从对象中,取出结构体变量的值
NSLog(@"%d-%d-%d", md1.year, md1.month, md1.day);
10、NSDate的介绍和使用
1)NSDate的介绍和使用
NSDate可以表示时间,可以进行一些常见的日期、时间处理。一个
NSDate对象就代表一个时间,[
NSDate date]返回的就是当前时间。
//NSDate
是
OC
中提供日期时间处理的一个类
//1 )获取当前时间
NSDate *d1 = [ NSDate date ]; // 创建一个日期时间对象对象
// 北京东八区,打印的时间 ( 格林威治时间 )+8 = 现在时间
//1 )获取当前时间
NSDate *d1 = [ NSDate date ]; // 创建一个日期时间对象对象
// 北京东八区,打印的时间 ( 格林威治时间 )+8 = 现在时间
NSLog(@"%@", d1);
//2
)格式化显示时间
NSDateFormatter *formatter = [ NSDateFormatter new ];
// 设置日期的显示格式
//yyyy: 年份 MM: 月份 dd: 天数
//HH:24 小时制 hh:12 小时制
//mm: 分钟数 ss: 秒数
formatter. dateFormat = @"yyyy 年 MM 月 dd 日 HH:mm:ss" ;
NSString *dateStr = [formatter stringFromDate :d1];
NSDateFormatter *formatter = [ NSDateFormatter new ];
// 设置日期的显示格式
//yyyy: 年份 MM: 月份 dd: 天数
//HH:24 小时制 hh:12 小时制
//mm: 分钟数 ss: 秒数
formatter. dateFormat = @"yyyy 年 MM 月 dd 日 HH:mm:ss" ;
NSString *dateStr = [formatter stringFromDate :d1];
NSLog(@"%@", dateStr);
//3
)计算时间
//1 、计算明天的此刻时间( 24 小时之后的时间)
NSTimeInterval t = 60 * 60 * 24 ;
NSDate *tom = [ NSDate dateWithTimeIntervalSinceNow :t];
NSDateFormatter *formatter = [ NSDateFormatter new ]; // 格式化显示
formatter. dateFormat = @"yyyy-MM-dd hh:mm:ss" ;
NSString *str = [formatter stringFromDate :tom];
NSLog ( @"%@" , str);
//2 、计算昨天的此刻时间( -t : 24 小时之前的时间)
NSDate *yest = [ NSDate dateWithTimeIntervalSinceNow :-t];
str = [formatter stringFromDate :yest];
NSLog ( @"%@" , str);
// 也可以用当前时间,进行加减时间
NSDate *now = [ NSDate date ];
NSDate *yest2 = [now addTimeInterval :-t]; // 该方法已经被放逐了
str = [formatter stringFromDate :yest2];
//1 、计算明天的此刻时间( 24 小时之后的时间)
NSTimeInterval t = 60 * 60 * 24 ;
NSDate *tom = [ NSDate dateWithTimeIntervalSinceNow :t];
NSDateFormatter *formatter = [ NSDateFormatter new ]; // 格式化显示
formatter. dateFormat = @"yyyy-MM-dd hh:mm:ss" ;
NSString *str = [formatter stringFromDate :tom];
NSLog ( @"%@" , str);
//2 、计算昨天的此刻时间( -t : 24 小时之前的时间)
NSDate *yest = [ NSDate dateWithTimeIntervalSinceNow :-t];
str = [formatter stringFromDate :yest];
NSLog ( @"%@" , str);
// 也可以用当前时间,进行加减时间
NSDate *now = [ NSDate date ];
NSDate *yest2 = [now addTimeInterval :-t]; // 该方法已经被放逐了
str = [formatter stringFromDate :yest2];
NSLog(@"%@", str);
//4
)日期时间对象的使用
//1 、 NSCalendar 日期类,可以帮助快速获取年月日 时分秒的信息
NSDate *d = [ NSDate date ];
// 创建日期对象
NSCalendar *cal = [ NSCalendar currentCalendar ];
// 参数:获取日期的哪个单元 ( 可以多个单元, |) 当前日期对象
NSDateComponents *com = [cal components : NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate :d];
NSLog ( @"%ld-%ld-%ld" , com. year , com. month , com. day );
//1 、 NSCalendar 日期类,可以帮助快速获取年月日 时分秒的信息
NSDate *d = [ NSDate date ];
// 创建日期对象
NSCalendar *cal = [ NSCalendar currentCalendar ];
// 参数:获取日期的哪个单元 ( 可以多个单元, |) 当前日期对象
NSDateComponents *com = [cal components : NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay fromDate :d];
NSLog ( @"%ld-%ld-%ld" , com. year , com. month , com. day );
//2、时间差方法:components:<#(NSCalendarUnit)#> fromDate:<#(nonnull NSDate *)#> toDate:<#(nonnull NSDate *)#> options:<#(NSCalendarOptions)#>
11、集合对象的内存管理
1)集合内存管理
//
创建对象
Person *p = [ Person new ]; //1
// 定义数组,并且把 P 放到数组中
// 规律:只要把对象放入数组, retainCount+1
Person *p = [ Person new ]; //1
// 定义数组,并且把 P 放到数组中
// 规律:只要把对象放入数组, retainCount+1
//NSArray *arr = [NSArray arrayWithObject:p];//2
NSMutableArray
*arr = [
NSMutableArray
array
];
[arr
addObject
:p];
//2
//上面都是快速创建对象,会被加入自动释放池。如果是[[NSArray alloc] init]、copy或new,则不会加入自动释放池,则该对象不会被释放,不会调用dealloc
NSLog
(
@"p.retainCount = %lu"
, p.
retainCount
);
[p release ];
// 规律 2 :数组被销毁时,对对象发送了一次 release 消息
// 销毁顺序:数组先挂 ----- 》数组向其中的对象也发送 release
NSLog ( @"p.retainCount = %lu" , p. retainCount );
// 结论:
//1 )当对象被添加到数组中,对象的引用计数 +1
//2 )数组被销毁时,对对象发送了一次 release 消息
[p release ];
// 规律 2 :数组被销毁时,对对象发送了一次 release 消息
// 销毁顺序:数组先挂 ----- 》数组向其中的对象也发送 release
NSLog ( @"p.retainCount = %lu" , p. retainCount );
// 结论:
//1 )当对象被添加到数组中,对象的引用计数 +1
//2 )数组被销毁时,对对象发送了一次 release 消息
//3)数组被销毁了,其中的对象不一定被销毁
2)集合内存管理总结
1、当调用alloc、new、copy(mutablecopy)方法产生一个新对象的时候,就必须在最后调用一次release或者autorelease。因为不会加入自动释放池。
2、retain和release必须成对出现
3、当一个对象添加集合,retain+1,retainCount+1
当一个集合(快速创建)被销毁,集合所有对象均被release一次,retainCount-1
当一个对象从集合中移除,这个对象会被release一次,retainCount-1
4、普遍规律:当方法名是add\insert开头 计数器+1
当方法名是remove\delete开头,计数器-1
12、copy概念及入门
1、copy概念
copy:复制,拷贝,是产生一个副本的过程。
对象拷贝的目的:要使用某个对象的数据,但是在修改对象的时候不影响原来的对象内容。
源文件和副本文件,互不影响。
copy功能:一个对象可以调用copy或mutableCopy方法创建一个副本对象
copy:创建不可变副本(如NSString)
mutableCopy:创建可变副本(如NSMutableString)
copy功能的前提:1)浅拷贝copy:需要遵守NSCopy协议,实现copyWithZone:方法
@protocol
NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end
2)深拷贝mutableCopy:需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
@protocol
NSMutableCopying
- (
id
)mutableCopyWithZone:(
nullable
NSZone
*)zone;
@end
2、copy快速入门
不可变对象,copy 产生不可变对象
不可变对象,mutableCopy 产生可变对象
可变对象,copy 产生不可变对象
可变对象,mutableCopy 产生可变对象
13、copy与内存管理
浅拷贝:只是拷贝了地址,并没有真正的分配新的内存空间(源对象引用计数+1,副本对象指向源对象,两者一样)
深拷贝:分配了新的内存空间(源对象引用计数不变,副本对象为1)
14、@property中的copy关键字
1)MRC:
1、copy:只用于NSString和block
2、retain:除NSString和block以外的对象
3、assign:基本数据类型、枚举、结构体(非OC对象)。当两个对象互相引用时,一段assign,一段retain
2)ARC:
1、
copy:只用于NSString和block
2、strong:
除NSString和block以外的对象
3、weak:当两个对象互相引用时,一段weak,一段strong
4、assign:
基本数据类型、枚举、结构体(非OC对象)
@property
(
nonatomic
,
copy
)
NSString
*name;
#import
<Foundation/Foundation.h>
#import
"Person.h"
int main( int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[ Person alloc ] init ];
NSMutableString *str = [ NSMutableString string ];
[str appendString : @"xxx" ];
p. name = str;
NSLog ( @"%@" , p. name );
// 使用 copy 时,防止这种无理的赋值。 name 得到的只是 str 的副本,再改变 str 不会影响 name
[str appendString : @"ooo" ];
NSLog ( @"%@" , p. name );
[p release ];
}
return 0 ;
int main( int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [[ Person alloc ] init ];
NSMutableString *str = [ NSMutableString string ];
[str appendString : @"xxx" ];
p. name = str;
NSLog ( @"%@" , p. name );
// 使用 copy 时,防止这种无理的赋值。 name 得到的只是 str 的副本,再改变 str 不会影响 name
[str appendString : @"ooo" ];
NSLog ( @"%@" , p. name );
[p release ];
}
return 0 ;
}
15、为自定义的类实现copy操作
步骤:1、新建Person类
2、为Person类实现copy操作
1)让Person类遵守NSCopying协议
2)实现copyWithZone方法,该方法返回一个对象的副本
3)在copyWithZone方法中,创建一个新的对象,并设置该对象的数据与现有对象一致,且返回该对象
3、创建Person对象,调用copy方法,查看地址
参数zone:表示空间,指定了zone,就可以指定新建对象对应的内存空间。如今开发中,zone几乎可以忽略
例子:1、
@interface
Dog :
NSObject
<
NSCopying
>
@property
(
nonatomic
,
assign
)
int
tuiNum;
@property
(
nonatomic
,
assign
)
int
speed;
@end
2、
@implementation
Dog
- (id)copyWithZone:(nullable NSZone *)zone {
NSLog
(
@"copy
完毕
"
);
//
互不影响,需申请新空间
Dog
*d = [[
Dog
alloc
]
init
];
d.
speed
=
self
.
speed
;
d.
tuiNum
=
self
.
tuiNum
;
//
返回新空间的地址
return
d;
}
@end
3、
Dog *dog = [ Dog new ];
dog. speed = 230 ;
dog. tuiNum = 8 ;
// 虽然重写 copyWithZone 方法,依然调用 copy 。历史原因
Dog *yellowDog = [dog copy ];
Dog *dog = [ Dog new ];
dog. speed = 230 ;
dog. tuiNum = 8 ;
// 虽然重写 copyWithZone 方法,依然调用 copy 。历史原因
Dog *yellowDog = [dog copy ];
NSLog(@"%d,%d", yellowDog.speed, yellowDog.tuiNum);
16、简单的单例模式实现
1)理解单例模式概念
单例模式(singleton):类的对象成为系统中唯一的实例,提供一个访问点,供客户类共享资源
单例使用场景:1、类只能够有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法
2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码
2)单例模式的实现
1、SingletonTools单例工具类
#import
<Foundation/Foundation.h>
@interface SingletonTools : NSObject < NSCopying >
@property ( nonatomic , assign ) int num;
@property ( nonatomic , copy ) NSString *text;
// 单例的类,提供一个接入点
+( instancetype )shareInstances;
@interface SingletonTools : NSObject < NSCopying >
@property ( nonatomic , assign ) int num;
@property ( nonatomic , copy ) NSString *text;
// 单例的类,提供一个接入点
+( instancetype )shareInstances;
//
防止创建新的对象或者破坏该单例对象
,需重写以下方法
-(
id
)copyWithZone:(
NSZone
*)zone;
+( id )allocWithZone:( NSZone *)zone;
-( id )retain;
-( NSUInteger )retainCount;
-( oneway void )release;
-( id )autorelease;
+( id )allocWithZone:( NSZone *)zone;
-( id )retain;
-( NSUInteger )retainCount;
-( oneway void )release;
-( id )autorelease;
@end
-------------------------------------------------------------------------------
#import
"SingletonTools.h"
// 定义一个全局变量
static SingletonTools *instances = nil ; //static 增长使用周期,下次使用还有值
@implementation SingletonTools
// 单例接入点方法
+( instancetype )shareInstances {
// 目的:保证对象必须唯一
if ( instances == nil ) {
// 创建一个对象
instances = [[ SingletonTools alloc ] init ];
return instances ;
}
return instances ;
}
// 防止创建新的对象或者破坏该单例对象,需重写以下方法
-( id )copyWithZone:( NSZone *)zone {
return self ;
}
+( id )allocWithZone:( NSZone *)zone {
// 线程保护
@synchronized ( self ) {
if ( instances == nil ) {
// 调用父类 alloc
instances = [ super allocWithZone :zone];
return instances ;//此处有待考究,没有关锁,就退出了
}
return instances ;
}
}
-( id )retain {
return self ;
}
-( NSUInteger )retainCount {
// 定义一个全局变量
static SingletonTools *instances = nil ; //static 增长使用周期,下次使用还有值
@implementation SingletonTools
// 单例接入点方法
+( instancetype )shareInstances {
// 目的:保证对象必须唯一
if ( instances == nil ) {
// 创建一个对象
instances = [[ SingletonTools alloc ] init ];
return instances ;
}
return instances ;
}
// 防止创建新的对象或者破坏该单例对象,需重写以下方法
-( id )copyWithZone:( NSZone *)zone {
return self ;
}
+( id )allocWithZone:( NSZone *)zone {
// 线程保护
@synchronized ( self ) {
if ( instances == nil ) {
// 调用父类 alloc
instances = [ super allocWithZone :zone];
return instances ;//此处有待考究,没有关锁,就退出了
}
return instances ;
}
}
-( id )retain {
return self ;
}
-( NSUInteger )retainCount {
return
1;
}
-( oneway void )release {
}
-( id )autorelease {
return self ;
}
-( oneway void )release {
}
-( id )autorelease {
return self ;
}
@end
2、Person类
#import
<Foundation/Foundation.h>
@interface Person : NSObject
-( void ) run;
@interface Person : NSObject
-( void ) run;
@end
----------------------------------------------------------------------------------------
#import
"Person.h"
#import "SingletonTools.h"
@implementation Person
-( void ) run {
// 创建单例对象
SingletonTools *st = [ SingletonTools shareInstances ];
st. num = 500 ;
st. text = @"xxxxx" ;
}
#import "SingletonTools.h"
@implementation Person
-( void ) run {
// 创建单例对象
SingletonTools *st = [ SingletonTools shareInstances ];
st. num = 500 ;
st. text = @"xxxxx" ;
}
@end
3、Dog类
#import
<Foundation/Foundation.h>
@interface Dog : NSObject
-( void )run;
@interface Dog : NSObject
-( void )run;
@end
--------------------------------------------------------------------------------------
#import
"Dog.h"
#import "SingletonTools.h"
@implementation Dog
-( void )run {
SingletonTools *st = [ SingletonTools shareInstances ];
NSLog ( @"%d,%@" , st. num , st. text );
}
#import "SingletonTools.h"
@implementation Dog
-( void )run {
SingletonTools *st = [ SingletonTools shareInstances ];
NSLog ( @"%d,%@" , st. num , st. text );
}
@end
4、main
#import
<Foundation/Foundation.h>
#import "Person.h"
#import "Dog.h"
int main( int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [ Person new ];
[p run ];
Dog *d = [ Dog new ];
[d run ]; // 通过单例, d 也可以访问 p 的数据
// 而且在重写方法后,并不需要在意在 Dog 类的 run 中是如何创建单例对象(快速或者 alloc )
// 单例实现了两个不相干的类的数据传输
}
return 0 ;
#import "Person.h"
#import "Dog.h"
int main( int argc, const char * argv[]) {
@autoreleasepool {
Person *p = [ Person new ];
[p run ];
Dog *d = [ Dog new ];
[d run ]; // 通过单例, d 也可以访问 p 的数据
// 而且在重写方法后,并不需要在意在 Dog 类的 run 中是如何创建单例对象(快速或者 alloc )
// 单例实现了两个不相干的类的数据传输
}
return 0 ;
}
Console:500,xxxxx