总结

编号 主题 内容
NSFileManager NSFileManager介绍/用法(常见的判断)/文件访问/文件操作
集合对象的内存管理 集合对象的内存管理/内存管理总结
*copy copy基本概念/使用/copy快速入门/内存管理
@Property中的copy关键字 @property中的copy的作用/@property内存管理策略选择
自定义类实现copy操作 自定义类实现copy操作
单例设计模式 单例模式概念/简单的单例模式实现
宏定义抽取单例

一. NSFileManager

1.NSFileManager介绍
  • 什么是NSFileManager

    • 顾名思义, NSFileManager是用来管理文件系统的
    • 它可以用来进行常见的文件\文件夹操作
  • NSFileManager使用了单例模式

    • 使用defaultManager方法可以获得那个单例对象
[NSFileManager defaultManager]
2.NSFileManager用法
  • - (BOOL)fileExistsAtPath:(NSString *)path;

    • path这个文件\文件夹是否存在
    NSFileManager *manager = [NSFileManager defaultManager];
// 可以判断文件
BOOL flag = [manager fileExistsAtPath:@"/Users/MJ-Hee/Desktop/lnj.txt"];
NSLog(@"flag = %i", flag);
// 可以判断文件夹
flag = [manager fileExistsAtPath:@"/Users/MJ-Hee/Desktop/未命名文件夹"];
NSLog(@"flag = %i", flag);
  • - (BOOL)fileExistsAtPath:(NSString )path isDirectory:(BOOL)isDirectory;

    • path这个文件\文件夹是否存在, isDirectory代表是否为文件夹
    NSFileManager *manager = [NSFileManager defaultManager];
BOOL directory = NO;
BOOL flag = [manager fileExistsAtPath:@"/Users/MJ-Hee/Desktop/未命名文件夹" isDirectory:&directory];
NSLog(@"flag = %i, directory = %i", flag, directory);
  • - (BOOL)isReadableFileAtPath:(NSString *)path;

    • path这个文件\文件夹是否可读
  • - (BOOL)isWritableFileAtPath:(NSString *)path;

    • path这个文件\文件夹是否可写
    • 系统目录不允许写入

  • - (BOOL)isDeletableFileAtPath:(NSString *)path;

    • path这个文件\文件夹是否可删除
    • 系统目录不允许删除

3.NSFileManager的文件访问
  • - (NSDictionary *)attributesOfItemAtPath:(NSString *)path error:(NSError **)error;

    • 获得path这个文件\文件夹的属性
    NSFileManager *manager = [NSFileManager defaultManager];
NSDictionary *dict = [manager attributesOfItemAtPath:@"/Users/MJ-Hee/Desktop/hmj.txt" error:nil];
NSLog(@"dit = %@", dict);
  • - (NSArray *)contentsOfDirectoryAtPath:(NSString *)path error:(NSError **)error;

    • 获得path的当前子路径
  • - (NSData )contentsAtPath:(NSString )path;

    • 获得文件内容
    • 只能获取当前文件夹下的所有文件,不能获取子文件夹下的文件
    NSFileManager *manager = [NSFileManager defaultManager];
NSArray *paths = [manager contentsOfDirectoryAtPath:@"/Users/MJ-Hee/Desktop" error:nil];
NSLog(@"paths = %@", paths);
  • - (NSArray )subpathsAtPath:(NSString )path;

  • - (NSArray *)subpathsOfDirectoryAtPath:(NSString *)path error:(NSError **)error;

    • 都能获得path的所有子路径
    • 第二个有error监听
    NSFileManager *manager = [NSFileManager defaultManager];
NSArray *paths = [manager subpathsAtPath:@"/Users/LNJ/Desktop/"];
NSLog(@"paths = %@", paths);
4.NSFileManager的文件操作
  • - (BOOL)copyItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;

    • 拷贝(生成新的)
  • - (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error;

    • 移动(剪切,不生成新的)
  • - (BOOL)removeItemAtPath:(NSString *)path error:(NSError **)error;

    • 删除
  • - (BOOL)createDirectoryAtPath:(NSString *)path withIntermediateDirectories:(BOOL)createIntermediates attributes:(NSDictionary *)attributes error:(NSError **)error;

    • 创建文件夹(createIntermediates为YES代表自动创建中间的文件夹)
    • createFileAtPath: 创建到那个位置
    • withIntermediateDirectories: 如果指定的文件中有一些文件夹不存在,是否自动创建不存在的文件夹
    • attributes:指定创建出来的文件夹的属性
    • error: 是否创建成功,失败的话会给传入的参数赋值
    NSFileManager *manager = [NSFileManager defaultManager];
BOOL flag = [manager createDirectoryAtPath:@"/Users/LNJ/Desktop/test" withIntermediateDirectories:YES attributes:nil error:nil];
NSLog(@"flag = %i", flag);
  • - (BOOL)createFileAtPath:(NSString )path contents:(NSData)data attributes:(NSDictionary *)attr;

    • 创建文件(NSData是用来存储二进制字节数据的)
    • createFileAtPath:指定创建文件的地址
    • contents:创建的文件的内容
    • attributes:指定创建出来的文件的属性
    NSString *str = @"lnj";
//NSData : 二进制数据
//将字符串转化成二进制数据
NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
NSFileManager *manager = [NSFileManager defaultManager];
BOOL flag = [manager createFileAtPath:@"/Users/LNJ/Desktop/abc.txt" contents:data attributes:nil];
NSLog(@"flag = %i", flag);
  • 注意

    • 该方法只能用于创建文件,不能用于创建文件夹

二.集合对象的内存管理

1.集合对象的内存管理
  • 当一个对象加入到集合中,那么该对象的引用计数会+1
  • 当集合被销毁的时候,集合会向集合中的元素发送release消息
    • 通过类对象创建的对象不需要release

      • NSMutableArray *arr = [NSMutableArray array];
    NSMutableArray *arr = [[NSMutableArray alloc] init];

    Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]);
//如果将一个对象添加到一个数组/字典中,那么数组会对对象进行一次retain
[arr addObject:p];
NSLog(@"retainCount = %lu", [p retainCount]);
[p release];
NSLog(@"retainCount = %lu", [p retainCount]);
//当数组对象释放后,会给数组中所有的对象发送一条release消息
[arr release];
  • 当一个对象加入到集合中,那么该对象的引用计数会+1
  • 当把一个对象从集合中移除时,会向移除的元素发送release消息
    NSMutableArray *arr = [[NSMutableArray alloc] init];
Person *p = [[Person alloc] init];
NSLog(@"retainCount = %lu", [p retainCount]);
[arr addObject:p];
NSLog(@"retainCount = %lu", [p retainCount]);
//当数组移除一个对象之后,会给这个对象发送一条release消息
[arr removeObject:p];
NSLog(@"retainCount = %lu", [p retainCount]);
[p release];
[arr release];
2.集合对象内存管理总结
  • 1.官方内存管理原则

    • 1> 当调用alloc、new、copy(mutableCopy)方法产生一个新对象的时候,就必须在最后调用一次release或者autorelease
    • 2> 当调用retain方法让对象的计数器+1,就必须在最后调用一次release或者autorelease
  • 2.集合的内存管理细节

    • 1> 当把一个对象添加到集合中时,这个对象会做了一次retain操作,计数器会+1
    • 2> 当一个集合被销毁时,会对集合里面的所有对象做一次release操作,计数器会-1
    • 3> 当一个对象从集合中移除时,这个对象会一次release操作,计数器会-1
  • 3.普遍规律

    • 1> 如果方法名是add\insert开头,那么被添加的对象,计数器会+1
    • 2> 如果方法名是remove\delete开头,那么被移除的对象,计数器-1

三.copy

1.copy基本概念
  • 什么是copy

    • Copy的字面意思是“复制”、“拷贝”,是一个产生副本的过程
  • 常见的复制有:文件复制

    • 作用:利用一个源文件产生一个副本文件
  • 特点:

    • 修改源文件的内容,不会影响副本文件
    • 修改副本文件的内容,不会影响源文件
  • OC中的copy

    • 作用:利用一个源对象产生一个副本对象
  • 特点:
    • 修改源对象的属性和行为,不会影响副本对象
    • 修改副本对象的属性和行为,不会影响源对象
2.Copy的使用
  • 如何使用copy功能

    • 一个对象可以调用copy或mutableCopy方法来创建一个副本对象
    • copy : 创建的是不可变副本(如NSString、NSArray、NSDictionary)
    • mutableCopy :创建的是可变副本(如NSMutableString、NSMutableArray、NSMutableDictionary)
  • 使用copy功能的前提

    • copy : 需要遵守NSCopying协议,实现copyWithZone:方法
@protocol NSCopying
- (id)copyWithZone:(NSZone *)zone;
@end
  • 使用mutableCopy的前提

    • 需要遵守NSMutableCopying协议,实现mutableCopyWithZone:方法
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(NSZone *)zone;
@end
  • 一般情况下,拷贝会生成一个新对象
2.深复制和浅复制
  • 不可变对象调用copy,不会生成一个新对象

    • 因为原来的和copy的对象都是不可变的,满足需求,所以不需要重新生成一个新对象
  • 浅复制(浅拷贝,指针拷贝,shallow copy)
    • 源对象和副本对象是同一个对象
    • 源对象(副本对象)引用计数器+1,相当于做一次retain操作
    • 本质是:没有产生新的对象
    NSString *srcStr = @"lnj";
NSString *copyStr = [srcStr copy];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
  • 深复制(深拷贝,内容拷贝,deep copy)

    • 源对象和副本对象是不同的两个对象
    • 源对象引用计数器不变,副本对象计数器为1(因为是新产生的)
    • 本质是:产生了新的对象
    NSString *srcStr = @"lnj";
NSMutableString *copyStr = [srcStr mutableCopy];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
[copyStr appendString:@" cool"];
NSLog(@"src = %@, copy = %@", srcStr, copyStr); NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
NSString *copyStr = [srcStr copy];
[srcStr appendString:@" cool"];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr); NSMutableString *srcStr = [NSMutableString stringWithFormat:@"lnj"];
NSMutableString *copyStr = [srcStr mutableCopy];
[srcStr appendString:@" cool"];
[copyStr appendString:@" 520it"];
NSLog(@"src = %p, copy = %p", srcStr, copyStr);
NSLog(@"src = %@, copy = %@", srcStr, copyStr);
  • 只有源对象和副本对象都不可变时,才是浅复制,其它都是深复制
  • 只有当源对象是不可变调用copy时才是浅拷贝
内存管理
  • 在iOS环境下运行
  • 总结 +如果是浅拷贝,那么系统会自动对源对象进行一次retain

    • 如果是深拷贝,会生成新对象,那么系统不会对源对象进行retain,但需要对新对象进行release
  • 浅拷贝的原则

    • alloc/new/retain/copy必须有对应的release

四.@Property中的copy关键字

1.@property中的copy的作用

  • 防止外界修改内部成员变量的值
    @interface Person : NSObject
//用retain,外界可以修改内部的数据,此处改为copy可以防止外界修改内部的数据
@property (nonatomic, retain) NSString *name;
@end NSMutableString *str = [NSMutableString stringWithFormat:@"lnj"]; Person *p = [[Person alloc] init];
p.name = str;
// person中的属性会被修改
[str appendString:@" cool"];
NSLog(@"name = %@", p.name);
  • 可以使用copy保存block,这样可以保住block中使用的外界对象的命
  • 防止访问对象时,对象已经释放
    • 不用copy情况

      Person *p = [[Person alloc] init];
      p.name = @"lnj";
      Dog *d = [[Dog alloc] init];
      d.age = 10;
      NSLog(@"retainCount = %lu", [d retainCount]); // 1
      p.pBlock = ^{
      // 报错, 调用之前就销毁了
      NSLog(@"age = %d", d.age);
      };
      [d release]; // 0
      p.pBlock();
      [p release];

    • 用copy情况
    Person *p = [[Person alloc] init];
p.name = @"lnj";
Dog *d = [[Dog alloc] init];
d.age = 10;
NSLog(@"retainCount = %lu", [d retainCount]); // 1
p.pBlock = ^{
// 会对使用到的外界对象进行一次retain
NSLog(@"age = %d", d.age);
NSLog(@"retainCount = %lu", [d retainCount]); // 1
};
[d release]; // 1
p.pBlock();
[p release];
  • copy block之后引发的循环引用

    • 如果对象中的block又用到了自己,那么为了泄露内存,应该将对象修饰为__block
2.@property内存管理策略选择
  • 非ARC

    • 1> copy : 只用于NSString\block
    • 2> retain : 除NSString\block以外的OC对象
    • 3> assign :基本数据类型、枚举、结构体(非OC对象),当2个对象相互引用,一端用retain,一端用assign
  • ARC

    • 1> copy : 只用于NSString\block
    • 2> strong : 除NSString\block以外的OC对象
    • 3> weak : 当2个对象相互引用,一端用strong,一端用weak
    • 4> assgin : 基本数据类型、枚举、结构体(非OC对象)
  • 注意

    • 只要是block使用copy,不是拷贝,而是将block从栈中转移到堆中
    • 只要

五. 自定义类实现copy操作

1.自定义类实现copy操作

  • 让类遵守NSCopying协议
  • 实现 copyWithZone:方法,在该方法中返回一个对象的副本即可。
  • 在copyWithZone方法中,创建一个新的对象,并设置该对象的数据与现有对象一致, 并返回该对象.
    • zone: 表示空间,分配对象是需要内存空间的,如果指定了zone,就可以指定 新建对象对应的内存空间。但是:zone是一个非常古老的技术,为了避免在堆中出现内存碎片而使用的。在今天的开发中,zone几乎可以忽略

  • 以后想让自定义的对象能够被copy,只需要遵守NSCopying协议
  • 实现协议中的-(id)copyWithZone(NSZone *)zone方法
  • 在-(id)copyWithZone(NSZone *)zone方法中创建一个副本对象,然后将当前对象的值赋值给副本对象即可

  • 无父类实现

-(id)copyWithZone(NSZone *)zone{

    //class用于获取一个类
CustomMode *custom = [[[self class] copyWithZone:zone] init]; Custom ->_a = [_a copyWithZone:zone]; Custom -> _c = _c;//不是对象的 直接赋值 Return custom; }
  • 有父类实现

    • 不调用父类方法, 无法拷贝父类中继承的属性
    • 不重新父类copyWithZone, 无法拷贝本来中的特有属性
    • 如果想让子类调用copy时,仍保留子类特有的属性,那么就需要重写copyWithZone,并在copyWithZone中调用父类的copyWithZone,即[super copyWithZone:zone]
-(id)copyWithZone(NSZone *)zone{

    CustomModel *custom = [super copyWithZone:zone];
//只调用子类特有的成员变量的setter方法即可
….
Return custom;
}

六.单例设计模式

  • 可以实现对象的共享
1.单例模式概念
  • 什么是单例模式:(Singleton)

    • 单例模式的意图是让类的对象成为系统中唯一的实例,供一个访问点,供客户类共享资源。
  • 什么情况下使用单例?

    • 1、类只能有一个实例,而且必须从一个为人熟知的访问点对其进行访问,比如工厂方法。
    • 2、这个唯一的实例只能通过子类化进行扩展,而且扩展的对象不会破坏客户端代码。
  • 单例设计模式的要点:

    • 1)某个类只能有一个实例。
    • 2)他必须自行创建这个对象
    • 3)必须自行向整个系统提供这个实例;
    • 4)这个方法必须是一个静态类
    • 5)一般情况下,创建一个单例对象都有一个与之对应的方法
    • 6)用于创建单例对象的方法名称都以share开头,或者以default开头
2.简单的单例模式实现
  • 调用alloc时,内部会调用allocWithZone
static 类名 *_instance = nil;
+ (instancetype)allowWithZone:(struct _NSZone *)zone
{
//由于所有的创建方法都会调用该方法,所以只需要在该方法中控制当前对象只创建一次即可
if (_instance == nil)
{
NSLog(@"创建了一个对象);
_instance = [[super allowWithZone:zone] init;
}
return _instance;
//以下代码在多线程中也能保证只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[super allowWithZone:zone] init];
} ;)
return _instance;
} //copyWithZone方法用什么调用?对象
- (id)copyWithZone:(NSZone *)zone
{
return _instance;
} - (id)mutableCopyWithZone:(NSZone *)zone
{
return _instance;
} - (oneway void) release
{
//为保证整个程序过程中只有一份实例,在这个方法中什么都不做
} - (instancetype)retain
{
return _instance;
} - (NSUInteger)retainCount
{
//注意:为了方便程序员之间沟通,一般情况下不会在单例中返回retainCount = 1,而是返回一个比较大的值
return MAXFLOAT;
}

七.宏定义抽取单例

// 如何判断当前是ARC还是MRC?
// 可以在编译的时候判断当前是否是ARC
#if __has_feature(objc_arc)
NSLog(@"ARC");
#else
NSLog(@"MRC");
#endif

/*********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 /********自定义类.h中********/ #import "Singleton.h" interfaceSingleton(类名); /********自定义类.m中********/ implementationSingleton(类名)

OC-copy,单例的更多相关文章

  1. iOS - OC SingleClass 单例类

    前言 单例对象能够被整个程序所操作.对于一个单例类,无论初始化单例对象多少次,也只能有一个单例对象存在,并且该对象是全局的,能够被整个系统访问到. 特点: 在内存中只有一个实例 提供一个全局的访问点 ...

  2. OC基础 单例

    #undef  AS_SINGLETON   #define AS_SINGLETON( __class ) \       + (__class *)sharedInstance;      #un ...

  3. OC 创建单例

    static BlockBackground *_sharedInstance = nil; + (BlockBackground*)sharedInstance { if (_sharedInsta ...

  4. 【Swfit】Swift与OC两种语法写单例的区别

    Swift与OC两种语法写单例的区别 例如写一个NetworkTools的单例 (1)OC写单例 + (instancetype)sharedNetworkTools { static id inst ...

  5. OC中两种单例实现方式

    OC中两种单例实现方式 写在前面 前两天探索了一下C++ 的单例,领悟深刻了许多.今天来看看OC中的单例又是怎么回事.查看相关资料,发现在OC中一般有两种实现单例的方式,一种方式是跟C++ 中类似的常 ...

  6. OC与Swift单例

    OC: +(instancetype)shareNetworkTools{ static id instance; static dispatch_once_t onceToken; //onceTo ...

  7. ios oc 和 swfit 用dispatch_once 创建单例

    网上已经有方法了,我这里就是抄了下,原文链接 http://bj007.blog.51cto.com/1701577/649413 http://blog.csdn.net/u010124617/ar ...

  8. OC中的单例设计模式及单例的宏抽取

    // 在一个对象需要重复使用,并且很频繁时,可以对对象使用单例设计模式 // 单例的设计其实就是多alloc内部的allocWithZone下手,重写该方法 #pragma Person.h文件 #i ...

  9. OC单例快速实现

    首先新建一个头文件,定义如下宏: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...

  10. iOS开发——多线程OC篇&多线程中的单例

    多线程中的单例 #import "DemoObj.h" @implementation DemoObj static DemoObj *instance; // 在iOS中,所有对 ...

随机推荐

  1. void * 是什么?

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它. 在哪遇到了? 线程创建函数pthread_create()的最后一个参数void *arg,嗯? ...

  2. java+selenium+testNG+Allure报表【新增截图到报表功能】

    1.pom.xml配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://w ...

  3. idea连接数据库时区:Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' prope

    错误界面 IDEA连接mysql,地址,用户名,密码,数据库名,全都配置好了,点测试连接,咔!不成功! 界面是这样的, 翻译过来就是:服务器返回无效时区.进入"高级"选项卡,手动设 ...

  4. C# 判断未将对象引用设置到对象的实例,出错的代码到底在第几行

    DataTable dt = null; try { var x = dt.Rows.Count; } catch(NullReferenceException nullexception) { Me ...

  5. Android Activity Deeplink启动来源获取源码分析

    一.前言 目前有很多的业务模块提供了Deeplink服务,Deeplink简单来说就是对外部应用提供入口. 针对不同的跳入类型,app可能会选择提供不一致的服务,这个时候就需要对外部跳入的应用进行区分 ...

  6. Spring Aop面向切面编程&&自动注入

    1.面向切面编程 在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面的过程叫做面向切面编程 2.常用概念 原有功能:切点,pointcut 前置通知:在切点之前执行的功能,befor ...

  7. [bzoj1146]网络管理

    发现是链上的问题,所以树链剖分发现要查询第k大,因为第k大不支持合并,所以要二分答案二分答案后相当于询问一些区间内大于某数的数个数,直接线段树套平衡树即可时间复杂度$o(nlog^{4}_n)$(跟$ ...

  8. [atARC085F]NRE

    令$(S_{a},S_{b})$表示$a_{i}\in S_{a}$且$b_{i}\in S_{b}$的i个数,那么答案相当于$S(0,1)+S(1,0)=S(0,1)+S(\{0,1\},0)-S( ...

  9. 第一章 初始C语言

    第一章 初始C语言 目录 第一章 初始C语言 1. C语言起源 2. 选择C语言的理由 2.1 设计特性 2.2 高效性 2.3 可移植性 2.4 强大而灵活 2.5 面向程序员 3. C语言的应用范 ...

  10. 9.1 k8s pod版本更新流程及命令行实现升级与回滚

    1.创建 Deployment root@k8-deploy:~/k8s-yaml/controllers/deployments# vim nginx-deployment.yaml apiVers ...