IOS開發學習筆記Day3-OC基礎三

NSArray

常用方法

//創建的兩種方式:
// 數組中的nil是結束符
NSArray *arr = [[NSArray alloc] init];
NSArray *arr = [NSArray arrayWithObject:@"lnj"];
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]);

if([arr containsObject:@"zs"])	{
	NSLog(@"arr中包含zs");
}else	{
	NSLog(@"arr中不包含zs");
}

// 創建數組簡寫
//    NSArray *arr = [NSArray arrayWithObjects:@"lnj", @"lmj", @"jjj", nil];
NSArray *arr = @[@"lnj", @"lmj", @"jjj"];
// 獲取數組元素的簡寫
NSLog(@"%@", [arr objectAtIndex:0]);
NSLog(@"%@", arr[0]);

數組的遍歷

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"];

數組的排序

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

array和String之間的轉換

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

將數組寫入到文件中

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

NSMutableArray(可變數組)

// 創建一個空的數組
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);
/*
// 如何刪除
[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"];*/

NSDictionary(字典)

// 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 *dict = @{@"name":@"lnj", @"age":@"30", @"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":@"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];

可變字典

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

常用的結構體

// 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開頭的結構體一般不用

NSNumber

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  [email protected];
NSLog(@"%@", temp);

NSValue

/*
typedef struct{
	int age;
	char *name;
	double _height;
}Person;

Person p = {30, "lnj", 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 = {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);

NSDate

// 1.NSDate創建和基本概念
/*
// 只要是通過date方法創建的時間對象, 對象中就保存了當前的時間
NSDate *now = [NSDate date];
NSLog(@"now = %@", now);
// 在now的基礎上追加多少秒
//    NSDate *date = [now dateByAddingTimeInterval:10];
//    NSLog(@"date = %@", date);

// 1.獲取當前所處的時區
NSTimeZone *zone = [NSTimeZone systemTimeZone];
// 2.獲取當前時區和指定時區的時間差
NSInteger seconds = [zone secondsFromGMTForDate:now];
//    NSLog(@"seconds = %lu", seconds);

NSDate *newDate = [now dateByAddingTimeInterval:seconds];
NSLog(@"newDate = %@", newDate);
*/

// 2.時間格式化  NSDate --> NSString
/*
// xxxx年xx月xx日 xx小時xx分鐘xx秒
// xxxx/xx/xx  xx/xx/xx
// xx/xx/xxxx  xx/xx/xx
NSDate *now = [NSDate date];

// 創建一個時間格式化對象
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
// 告訴時間格式化對象, 按照什麼樣的格式來格式化時間
// yyyy 年
// MM 月
// dd 日
// HH 24小時  hh 12小時
// mm 分鐘
// ss 秒鐘
// Z 時區
//    formatter.dateFormat = @"yyyy年MM月dd日 HH時mm分ss秒 Z";
formatter.dateFormat = @"MM-dd-yyyy HH-mm-ss";

// 利用時間格式化對象對時間進行格式化
NSString *res = [formatter stringFromDate:now];
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);

NSCalendar

// 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);

NSFileManager

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];

對象的copy

/*
// 會生成一個新的對象
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方法有時候會生成一個新的對象, 有時候不會生成一個新的對象
所以: 如果沒有生成新的對象, 我們稱之爲淺拷貝, 本質就是指針拷貝
如果生成了新的對象, 我們稱之爲深拷貝, 本質就是會創建一個新的對象
*/

Person.h
@interface Person : NSObject<NSCopying, NSMutableCopying>

@property (nonatomic, assign) int age;

@property (nonatomic, copy) NSString *name;
@end


Person.m

#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

    /*
     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);
//    Person *p2 = [p copy];
    Person *p2 = [p mutableCopy];
    
    NSLog(@"%@", p2);
    */
    
    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);

宏的高級使用(生成單例代碼)

// 以後就可以使用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

使用反斜槓代表在一行也是宏定義。,宏名稱後面傳遞參數可以用## (雙井號)+名稱可以使用。例如:
#define 名稱(參數名)後面如果需要使用宏裏面的參數,##參數名

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章