OC-copy,單例

總結

編號 主題 內容
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這個文件\文件夾是否可寫
    • 系統目錄不容許寫入app

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

    • path這個文件\文件夾是否可刪除
    • 系統目錄不容許刪除spa

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)他必須自行建立這個對象
    • 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(類名)
相關文章
相關標籤/搜索