你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS編程技術 >> OC學習心得【適合初學者】

OC學習心得【適合初學者】

編輯:IOS編程技術

一、類和對象

1.OC語言是C語言的擴充,並且OC是iOS和OS X操作系統的編程語言。

①具備完善的面向對象特性:

封裝:將現實世界中存在的某個客體的屬性與行為綁定在一起,並放置在一個邏輯單元內

繼承:子類自動共享父類數據結構和方法的機制,這是類之間的一種關系

多態:指相同的操作或函數、過程可作用於多種類型的對象上並獲得不同的結果

②內存管理機制有GC(垃圾回收機制)和RC(引用計數機制【MRC和ARC】),但是iOS支持兩種內存管理方式:ARC和MRC。

③面向對象的核心思想是類和對象

2.類:具有相同特征和行為的事物的抽象。【是對象的類型】

①類的定義分為:接口部分和實現部分

<1>接口部分:對外聲明類的特征和行為。(.h文件中)

標志:@interface...@end【作用;聲明類名,類的繼承(父類),遵循的協議,實例變量和方法(特征和行為)】

<2>實現部分:行為的具體實現。(.m文件中)

標志:@implementation...@end【方法的實現】

3.對象:類的實例

①對象的創建

<1>分配內存空間:堆區分配內存,並返回首地址。

<2>初始化:為對象的實例變量設置初始值【init將內存空間的數據清零】

  Teacher *teacher = [[Teacher alloc] init]; 

指針(teacher)存儲對象的首地址,代指對象,進行操作

4.instancetype和id區別

①instancetype可以返回和方法所在類相同類型的對象,id只能返回未知類型的對象。

②instancetype只能作為返回值和參數,id還可以用來定義變量

5.實例變量

①實例變量變量可見度

@interface Child : NSObject
{
    @public// 作用范圍:外部、內部、繼承
    NSString *_name;
    @protected// 【系統默認】作用范圍:內部、繼承
    NSInteger _age;
    @private// 作用范圍:內部
    CGFloat _score;
}
@end

②實例變量必須在花括號內

6.方法

①類中不能出現同名方法

②“:”標識參數,不能省略。有冒號必須有參數。

③冒號屬於方法名的一部分

④“+”類方法

⑤“-”實例方法

// 方法名:printNum:
// 有參(1個參)無返回值
- (void)printNum:(NSInteger)num;
// 有兩個參數
// 方法名:printName:age:
- (void)printName:(NSString *)name age:(NSInteger)age;

//有三個參數
//方法名:printName:age:score:
- (void)printName:(NSString *)name age:(NSInteger)age score:(CGFloat)score;

7.在OC中使用消息發送機制:[receiver message]

表述:

①給received對象發送message消息

②received接收到消息,即方法message

③teacher找到message方法,並執行。

8.setter和getter方法

①setter(設置器)

<1>格式

- (void)setAge:(NSInteger)age;

即set+首字母大寫的實例變量名(忽略下劃線)

②getter(訪問器)

<1>格式

- (NSInteger)age;

即返回值類型與變量類型一致,方法名與實例變量名相同(忽略下劃線)

③無論setter還是getter內部操作的是實例變量

④每一個實例變量都需要一對setter和getter方法

⑤點語法只對setter和getter方法有效

9.@class的作用

只是表示有這麼個類型,其他什麼都沒做。【注意:一般在.h中使用@class,在.m中引入頭文件】

 

二、初始化方法

1.繼承

①保證類的完整,簡化代碼

②NSObject是根類

③繼承的內容:所有實例變量和方法

④繼承是單向的,不能相互繼承

⑤繼承具有傳遞性

⑥子類可以重寫父類的方法

2.super

①編譯器指令,並非對象

②作用:給super發消息,可以執行父類該方法的實現

3.self

①系統關鍵字

②self在方法中指代當前方法的調用者

在實例方法中,指代調用當前方法的對象

在類方法中,指代當前類

4.初始化方法

①作用:為某些實例變量賦初值

②初始化方法在對象的整個生命周期裡只使用一次【注:初始化方法是在對象的初始化階段完成其實例變量的賦值操作,一個對象的初始化階段只有一次,所以初始化方法只使用一次】

③“-”實例方法

- (instancetype)init{
    // self在實例方法中代表實例對象
    // self在類方法中代表類
    self = [super init];
    // 判斷從父類繼承過來的init方法是否初始化成功
    if (self != nil) {//if(self)  //if(self = [super init])  非零即為真
        // 初始化實例變量
        _name = @"大白";
    }
    // 返回初始化完成的對象
    return self;
}

<1>使用super調用父類的初始化方法,用於初始化繼承自父類的公共實例變量
<2>初始化完成之後會返回一個地址,這個地址就是對象的地址
<3>self是一個指針,指向自己的對象。self保存返回的地址。再初始化自身特有變量。
<4>返回值有可能為空。如果返回值為空,就什麼也不做。返回值不為空,初始化自己的實例變量。

5.指定初始化方法

①一個類可以有多個初始化方法

②雖然可以有多個初始化方法,但是一個對象只能使用一個初始化方法。

③通常會把在初始化時想做的操作全部放到指定初始化方法中

④選取原則:一般選參數最多的初始化方法作為指定初始化方法

⑤情況1:

.h中聲明

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age;

.m中實現

- (instancetype)initWithName:(NSString *)name age:(NSInteger)age{
    
    if (self = [super init]) {
        _name = name;
        _age = age;
    }
    return self;
}

⑥情況2:

.h聲明

- (instancetype)initWithName:(NSString *)name;

- (instancetype)initWithName:(NSString *)name Age:(NSInteger)age;

- (instancetype)initWithName:(NSString *)name Age:(NSInteger)age Score:(CGFloat)score;

.m實現

#import "Student.h"
@implementation Student
- (instancetype)initWithName:(NSString *)name Age:(NSInteger)age Score:(CGFloat)score{
    
    if (self = [super init]) {
        _name = name;
        _age = age;
        _score = score;
    }
    return self;
}

- (instancetype)initWithName:(NSString *)name Age:(NSInteger)age{
    //凡是基本數據類型填0,對象、類填nil
    return [self initWithName:name Age:age Score:0];
}

- (instancetype)initWithName:(NSString *)name{
    
    return [self initWithName:name Age:0 Score:0];
}
@end

6.便利構造器

①內部實現:封裝了alloc和初始化操作,創建對象更加方便

②“+”類方法

③返回本類型的實例

④方法名以類名開頭

⑤可以有0到多個參數

.聲明

+ (instancetype)teacherWithName:(NSString *)name age:(NSInteger)age;

.實現

+ (instancetype)teacherWithName:(NSString *)name age:(NSInteger)age{
    
    Teacher *t = [[Teacher alloc]initWithName:name age:age];
    return t;
}

.調用

Teacher *t2 = [Teacher teacherWithName:@"Lee" age:13];

 

三、屬性和點語法

1.屬性

①提供setter、getter方法的默認實現

②關鍵字:

@property(聲明)

@synthesize(實現)【可以省略,沒有實現setter和getter方法時,通過該關鍵字自動生成】

③如果方法內部操作的實例變量未定義,系統會自動生成一個_屬性名的實例變量,但是生成的實例變量的可見度是私有的,子類不可訪問。

④一旦同時重寫了setter、getter方法,並且沒有實現@synthesize,@synthesize就不再生成實例變量。需要寫@synthesize

2.屬性特性

①讀寫性

readonly:只讀狀態(只生成getter方法)

readwrite:讀寫狀態(setter和getter方法都生成)【系統默認】

setter=:指定屬性生成的setter方法的名字

getter=:指定屬性生成的getter方法的名字

②原子性

atomic:原子特性。setter、getter內部做了多線程處理。【系統默認】

nonatomic:非原子特性,生成普通setter、getter方法。【通常使用】

③語義特性

<1>MRC(手動引用計數)

assgin:非對象類型(比如int、float)屬性的語義設置

@property (nonatomic, assign) NSInteger age;
setter?方法內部實現:
   - (void)setAge:(NSInteger)age {
     _age = age;
}
getter?方法內部實現:
   - (NSInteger)age {
     return _age;
}

retain:對象類型(比如:NSString,NSMutableDictionary等)屬性的語義設置

@property (nonatomic, retain) NSString *name;
setter?方法內部實現:
- (void)setName:(NSString *)name {
  if (_name != name) {
      [_name release];
      _name = [name retain];
  }
}
getter?方法內部實現:
- (NSString *)name {
  return  [[_name retain] autorelease];
}

copy:對象類型並且想得到對象的副本(NSString)

@property (nonatomic, copy) NSString *gender;
setter內部實現
 - (void)setGender:(NSString *)gender {
   if (_gender != gender) {
       [_gender release];
       _gender = [gender copy];
   }
}
getter內部實現
 - (NSString *)gender {
   return  [[_gender retain] autorelease];
}

跟retain不同,一個對象想要copy,生成自己的副本,需要服從

<2>ARC(自動引用計數)

assign:修飾基本數據類型

weak:修飾類對象

strong:修飾類對象

copy:修飾類對象

 

四、OC字符串和數值

1.API文檔

①Xcode -> Help ->Documentation and API Reference

Inherits form 繼承關系

Conforms to 遵循什麼協議

framework 屬於哪個框架

Availability 什麼時候可以用

Declared in 聲明在什麼頭文件裡

Related documents 相關文檔

Sample code 示例代碼

②option+鼠標左鍵

③command+鼠標左鍵

2.字符串(NSString和NSMutableString)

①OC中字符串由unichar(unicode)組成

②NSString字符串(不可變)

<1>創建

     // 創建字符串(錯誤)
    // NSString是不可變字符串,意味著創建之後不能改變,使用init完成之後字符串就創建完了,只得到一個空字符串。
    NSString *s2 = [[NSString alloc] init];
    
    // 正確創建字符串
    // 格式化初始字符串
    NSString *s3 = [[NSString alloc] initWithFormat:@"Lanou%@",s1];
    //便利構造器
    NSString *s4 = [NSString stringWithFormat:@"Lanou%@",s1];
    // 字面量
    NSString *s5 = @"hello";

<2>常用方法

    NSString *str1 = @"abcdefg";
    // 獲取字符串長度
    NSLog(@"%ld",[str1 length]);
    
    // 獲取指定位置的字符(不推薦)
    unichar c = [str1 characterAtIndex:4];

    // 判斷字符串是否相等
    BOOL b = [str1 isEqualToString:@"abcdefg"];

    // 比較兩個字符串大小
    NSComparisonResult result = [str1 compare:@"bbb"];
    
    // 截取子串
    // 從哪開始截取
    NSString *str2 = [str1 substringFromIndex:4];
    
    // 從開始到哪結束
    NSString *str3 = [str1 substringToIndex:2];
    
    // 從哪開始截取,到哪裡結束(獲取單個字符使用這個方法)
//    NSRange r = {0,3};
    NSString *str4 = [str1 substringWithRange:NSMakeRange(2, 1)];
    
    // 拼接字符串
    NSString *str5 = [str1 stringByAppendingFormat:@"hi"];
    
    // 替換字符串
    NSString *str6 = [str1 stringByReplacingCharactersInRange:NSMakeRange(1, 6) withString:@"xxx"];
    
    // 字符串對象轉化為int型
    // 注意:不要在數字中加入字符,否則字符在哪就在哪停止
    NSString *str7 = @"123";
    NSInteger i = [str7 intValue];

    // int轉為字符串
      NSString *str1 = [NSString stringWithFormat:@"%d",number];

    // 字符串全部大寫
    NSString *str8 = [str1 uppercaseString];
    
    // 字符串全部小寫
    NSString *str9 = [str1 lowercaseString];
    
    // 字符串首字母大寫
    NSString *str10 = [str1 capitalizedString];
    
    // 判斷後綴(重點)
    // 後綴:以字符串最後一個字符結尾的子串
    // 前綴:以首字母開頭的子串
    
    // 是否以指定字符串為後綴
    BOOL b2 = [str1 hasSuffix:@"g"];
    
    // 是否以指定字符串為前綴
    BOOL b3 = [str1 hasPrefix:@"a"];

②NSMutableString(動態可變字符串)

<1>創建

Capacity參數值為預估的空間大小,但是會根據實際的存儲情況,動態的調整實際空間大小【翻倍】

初始化方法
    NSMutableString *strm1 = [[NSMutableString alloc] initWithCapacity:100];

<2>常用方法

// 拼接字符串
    [strm1 appendFormat:@"123"];

// 在哪裡插入字符串
    [strm1 insertString:@"000" atIndex:1];

// 刪除字符串
    [strm1 deleteCharactersInRange:NSMakeRange(1, 3)];

// 替換字符串
    [strm1 replaceCharactersInRange:NSMakeRange(1, 1) withString:@"5"];

// 重置字符串
    [strm1 setString:@"abc"];

 3.數值類(NSNumber)

①作用:實現基本數據類型與OC對象類型的相互轉化

②基本數據類型(int,float等)轉換為NSNumber

// int類型轉化為NSNumber類型的對象
    + (NSNumber *)numberWithInt:(int)value;
// float類型轉化為NSNumber類型的對象
    + (NSNumber *)numberWithFloat:(float)value;
// char類型轉化為NSNumber類型的對象
    + (NSNumber *)numberWithChar:(char)value;

③NSNumber轉換為基本數據類型(int,float等)

// NSNumber類型對象轉化為int類型的數據
    @property (readonly) int intValue;
// NSNumber類型對象轉化為float類型的數據
    @property (readonly) float floatValue;
// NSNumber類型對象轉化為char類型的數據
    @property (readonly) char charValue;

④常用方法

// NSNumber類型對象的?比較
- (NSComparisonResult)compare:(NSNumber *)otherNumber;

⑤字面量

// 常量:
    NSNumber *intNumber = @38;
    NSNumber *charNumber = @‘w';
// 變量:
    int age = 18;
    NSNumber *ageNumber = @(age);
    char gender = 'w';
    NSNumber *genderNumber = @(gender);

4.NSValue(完成結構體和對象類型的轉換)

①結構體(NSRange等)轉換為NSValue

②NSValue轉換為結構體(NSRange等)

③常用方法

// NSRange類型轉化為NSValue類型的對象
+ (NSValue *)valueWithRange:(NSRange)range;
// NSValue類型轉化為NSRange類型的結構體變量
@property (readonly) NSRange rangeValue;

 

五、集合

1.數組類(NSArray和NSMutableArray)

①只能存儲對象類型,但是對於對象的類型沒有限制【有序的集合】

②NSArray(不可變數組)

<1>創建

// 注意:nil作為數組的結束標志,不要手動添加。
// 初始化方法
    NSArray *arr1 = [[NSArray alloc] initWithObjects:@"a",@"b",@"c", nil];
// 便利構造器
    NSArray *arr2 = [NSArray arrayWithObjects:@"d",@"e",@"f",@"g",nil];
// 字面量(結尾不需要加nil)
    NSArray *arr3 = @[@"mike",@"Joe",@"kitty"];

<2>常用方法

// 獲取元素個數
    NSUInteger c1 = arr1.count;//[arr1 count]

// 獲取數組中指定下標對應的元素
    NSString *obj1 = [arr3 objectAtIndex:0];

// 字面量獲取元素
    NSLog(@"%@",arr3[2]);

// 判斷數組中是否包含某個元素
    BOOL b1 = [arr1 containsObject:@"m"];

// 返回一個元素在數組中的索引
    NSUInteger n1 = [arr1 indexOfObject:@"b"];

// 分割字符串
    NSString *str1 = @"www.lanou3g.com";
    NSArray *arr4 = [str1 componentsSeparatedByString:@"."];

// 拼接字符串
    NSString *str2 = [arr4 componentsJoinedByString:@"/"];
    NSLog(@"%@",str2);

③NSMutableArray(可變數組)

<1>創建

// 初始化方法
     NSMutableArray*marr1 = [[NSMutableArray alloc]initWithCapacity:10];

// 便利構造器
    NSMutableArray *marry2 = [NSMutableArray arrayWithCapacity:10];

// 可變數組使用字面量(字面量創建的數組是不可變的)
    NSMutableArray *marr3 =@[@"a",@"b",@"c"].mutableCopy
//[@[@"a",@"b",@"c"] mutableCopy]點語法getter

<2>常用方法

// 添加元素
    [marr1 addObject:@"a"];

// 插入元素
    [marr1 insertObject:@"x" atIndex:2];

// 刪除元素
    //按元素刪
    [marr1 removeObject:@"x"];
    //按位置刪
    [marr1 removeObjectAtIndex:0];
    // 刪除最後一個
    [marr1 removeLastObject];
    // 刪除全部
    [marr1 removeAllObjects];

// 使用指定元素替換指定位置上的元素
    [marr4 replaceObjectAtIndex:marr4.count - 1 withObject:@"e"];

// 交換兩個指定位置的元素
    [marr4 exchangeObjectAtIndex:0 withObjectAtIndex:3];

2.字典類(NSDictionary和NSMutableDictionary)

①用來存儲一一對應關系的數據【無序的集合】

②key和value必須是對象類型,每一對稱為一個條目

③靠key存取元素

④NSDictionary(不可變字典)

<1>創建

// 初始化方法
     NSDictionary*dict1 = [[NSDictionaryalloc]initWithObjectsAndKeys:@"Mike",@"M",@"Lee",@"L",@"Kitty",@"K",nil];

// 字面量
    NSDictionary *dict2 = @{@"M":@"Mike",@"L":@"Lee",@"K":@"Kitty"};

<2>常用方法

// 獲取鍵值對個數
    NSUInteger c1 = dict1.count;//[dict1 count]

// 獲取字典中所有的key值
    NSArray *arr1 = dict1.allKeys;//[dict1 allKeys]

// 獲取字典中所有的value
    NSArray *arr2 = dict1.allValues;//[dict1 allValues]

// 根據key獲得對應的value
    NSString *obj1 = [dict1 objectForKey:@"M"];

// 字面量獲取
    NSString *obj2 = dict1[@"L"];

//注意:在字典中key不能重復
    NSDictionary *dict3 =@{@"M":@"Mike",@"L":@"Lee",@"T":@"Tim",@"L":@"Lucy"};

⑤NSMutableDictionary(不可變數組)

<1>創建

// 初始化方法
    NSMutableDictionary *mdict1 = [[NSMutableDictionary alloc] initWithCapacity:10];

// 字面量
    NSMutableDictionary *mdict2 = @{@"M":@"Mike",@"L":@"Lee"}.mutableCopy;

<2>常用方法

// 添加(如果字典中沒有給定的key,就添加這個鍵值對)
    [mdict2 setValue:@"Tim" forKey:@"T"];

// 修改(如果字典中有給定的key,直接修改value)
    [mdict2 setObject:@"Lucy" forKey:@"L"];

// 給定key刪除
    [mdict2 removeObjectForKey:@"M"];

// 刪除所有鍵值對
    [mdict2 removeAllObjects];

 3.集合類(NSSet和NSMutableSet)

①互異性、無序性,經常用來處理重用問題

②NSSet(不可變集合)

<1>創建

// 初始化?方法
NSSet *name = [[NSSet alloc] initWithObjects:@"frank", @"duck", @"monkey",nil];

// 便利構造器
 NSSet *name = [NSSet setWithObjects:@"frank",@"duck", @"monkey", nil];

<2>常用方法

// 元素個數
    NSLog(@"%ld",set.count);

// 將set中的所有元素放到數組中
    NSArray *setArr = set.allObjects;

// 任意取出一個元素
    NSString *s1 = [set anyObject];

// 判斷set中是否包含給定對象
    BOOL b = [set containsObject:@"6"];

③NSMutableSet(可變集合)

<1>創建

// 初始化?方法
NSMutableSet *name = [[NSMutableSet alloc] initWithCapacity:0];

// 便利構造器
NSMutableSet *name = [NSMutableSet setWithCapacity:0];

<2>常用方法

// 添加?一個對象
   - (void)addObject:(id)object;
// 移除?一個對象
   - (void)removeObject:(id)object;
// 移除所有對象
  - (void)removeAllObjects;

 

六、集合遍歷和數組排序

1.for循環遍歷

①原理:通過for循環的循環變量用作數組元素下標來獲取不同下標的元素

②循環次數就是數組元素的個數

<1>遍歷數組

    NSArray *arr = @[@"Mike",@"Lee",@"Kitty"];
    for (int i = 0 ; i < arr.count ; i ++) {
        NSLog(@"%@",arr[i]);
    }

<2>遍歷字典

    NSDictionary *dict = @{@"M":@"Mike",@"L":@"Lee",@"K":@"Kitty"};
    // 獲取key
    NSArray *keyArr = dict.allKeys;
    // 遍歷數組
    for (int i = 0 ; i < keyArr.count; i ++) {
        NSLog(@"%@",dict[keyArr[i]]);//[dict objectForKey:keyArr[i]]
    }

<3>遍歷集

    NSSet *set = [NSSet setWithObjects:@"1",@"2",@"3", nil];
    // 將集合中的元素放到數組中
    NSArray *allArr = set.allObjects;
    for (int i = 0 ; i < allArr.count; i ++) {
        NSLog(@"%@",allArr[i]);
    }

2.枚舉器(NSEnumeration)

①遍歷集合中的元素

②依附於集合類,沒有用來創建實例的接口

③對可變集合進行枚舉操作,不能通過添加或刪除對象這類方式改變集合容器的元素個數

④注意:由於字典和集合中存儲的元素是無序的,因此沒有反向枚舉的概念

<1>數組

    NSArray *arr2 = @[@"1",@"2",@"3"];
    // 創建枚舉器(必須依靠一個容器對象)
    // 正向
    NSEnumerator *enum1 = [arr2 objectEnumerator];
    // 創建一個保存取出元素的變量
    id value1 = nil;
    // 循環取值
    while (value1 = [enum1 nextObject]) {
        NSLog(@"%@",value1);
    }

    // 逆向
    NSEnumerator *enum2 = arr2.reverseObjectEnumerator;
    // 創建一個保存取出元素的變量
    id value2 = nil;
    // 循環取值
    while (value2 = [enum2 nextObject]) {
        NSLog(@"%@",value2);
    }

<2>字典

    NSDictionary *dict2 = @{@"M":@"Mike",@"L":@"Lee",@"K":@"Kitty"};
    // 創建枚舉器
    NSEnumerator *enum3 = [dict2 objectEnumerator];
    // 創建一個保存取出元素的變量
    id value3 = nil;
    // 循環變量
    while (value3 = [enum3 nextObject]) {
        NSLog(@"%@",value3);
    }

<3>集

    NSSet *set2 = [NSSet setWithObjects:@"1",@"2",@"3", nil];
    // 創建枚舉器
    NSEnumerator *enum4 = [set2 objectEnumerator];
    // 創建一個保存取出元素的變量
    id value4 = nil;
    // 循環變量
    while (value4 = [enum4 nextObject]) {
        NSLog(@"%@",value4);
    }

3.for...in

①對可變集合進行快速枚舉操作時,不能通過添加或刪除對象這類方式來改變集合容器的元素個數

<1>數組

    NSArray *arr3 = @[@"1",@"2",@"3"];
    for (NSString *str in arr3) {
        NSLog(@"%@",str);
    }

<2>字典

    NSDictionary *dict3 = @{@"M":@"Mike",@"L":@"Lee",@"K":@"Kitty"};
    // 取出key
    for (NSString *s in dict3) {
        NSLog(@"%@",s);
    }
    // 取出value
    for (NSString *s1 in dict3) {
        NSLog(@"%@",dict3[s1]);
    }

<3>集

    NSSet *set3 = [NSSet setWithObjects:@"1",@"2",@"3", nil];
    for (NSString *s1 in set3) {
        NSLog(@"%@",s1);
    }

4.數組排序

①數組是有序容器,因此集合中只有數組才能排序

②NSSortDescriptor

// 初始化方法
     - (instancetype)initWithKey:(NSString *)key  ascending:(BOOL)ascending;
// 數組根據排序條件進?行排序,得到排好序的新的數組對象。
     - (NSArray*)sortedArrayUsingDescriptors:(NSArray *)sortDescriptors;
sortDescriptors:數組類型的對象,數組中可以存放多個排序描述對 象,最終能夠實現按照多個要求進?行排序的?目的。 ?如:如果該參數中存儲了由name和age兩個Person屬性參與創建 的NSSortDescriptor對象,在按name進?行排序的同時,如果遇到姓名相同的就會按照age進?行排序。 <1>數組中存放自定義類的對象
// 創建數組對象
NSArray *array = @[@"zhegnzhou", @"beijing",@"shanghai", @"guangzhou", @"xian", @"dalian"];
// 創建排序條件
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES];
// 數組根據排序條件進?行排序
NSArray *resultArray = [array sortedArrayUsingDescriptors:@[descriptor]];

<2>數組中存放直接可進行排序的對象

// 創建數組對象,數組中存儲多個Person對象
NSArray *array = @[per1, per2, per3, per4, per5];
// 創建排序條件,按照Person對象的姓名降序排序
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
// 數組根據排序條件進?行排序
NSArray *resultArray = [array sortedArrayUsingDescriptors:@[descriptor]];

③其他數組排序方法

<1>不可變數組排序(排序結果生成新數組,原數組無改變)

 - (NSArray *)sortedArrayUsingSelector:(SEL)comparator;
// 注:SEL類型的參數comparator:需要傳入一個返回結果是 NSComparisonResult的方法名。
NSArray *array = @[@"lanou", @"zhengzhou", @“henan",@“huimian"];
NSArray *newArray = [array sortedArrayUsingSelector:@selector(compare:)];

數組array中的元素都是字符串。字符串比較的方法compare:返回值類型正好滿足SEL參數的需求

<2>可變數組排序(直接對原數組進行操作,無新數組生成)

     (void)sortUsingSelector:(SEL)comparator;
// 注:SEL類型的參數comparator:需要傳入一個返回結果是 NSComparisonResult的函數

<3>數組中存放自定義的類的對象

NSArray *personArray = @[p1,p2,p3,p4,p5];

// 按姓名升序
NSArray *newNameArrayAscending = [personArray sortedArrayUsingSelector:@selector(compareByNameAscending:)];

// 按姓名降序
NSArray *newNameArrayDescending = [personArray sortedArrayUsingSelector:@selector(compareByNameDescending:)];
比較方法的聲明
// 按姓名升序
- (NSComparisonResult)compareByNameAscending:(Person *)anotherPerson;

// 按姓名降序
- (NSComparisonResult)compareByNameDescending:(Person *)anotherPerson;
比較方法的實現
// 按姓名升序
- (NSComparisonResult)compareByNameAscending:(Person *)anotherPerson{

    return [self.name compare:anotherPerson.name];

}

// 按姓名降序
- (NSComparisonResult)compareByNameDescending:(Person *)anotherPerson{

    if (self.name < self.name) {

        return 1;

    }else{

        return 0;

    }

}

 

七、內存管理

1.OC內存管理的機制(GC和RC)

①GC:垃圾回收機制(Garbage-Collection)

程序員只需開辟內存空間,不需要用代碼的形式釋放,系統來判斷哪些空間不再被使用,並回收這些內存空間,以便再次分配。整個回收的過程不需要寫任何代碼,由系統自動完成垃圾回收。Java開發中一直使用的就是垃圾回收技術。

②RC:引用計數機制(MRC和ARC)【iOS支持的兩種內存管理方式】

<1>MRC(Manual Reference Counting)人工引用計數【內存管理機制:引用計數】

內存的開辟和釋放都由程序代碼進行控制。相對垃圾回收來說,對內存的控制更加靈活,可以在需要釋放的時候及時釋放。

<2>ARC(Auto Reference Counting)自動引用計數【基於MRC】

iOS 5.0的編譯器特性,它允許用戶開辟空間,不用去釋放空間。它不是垃圾回收!它的本質還是MRC,只是編譯器幫程序員默認加了釋放的代碼。

2.引用計數機制【棧結構的先進後出】

①每個對象都有一個引用計數器,用來記錄當前對象的引用次數

②當一個新的引用指向對象時,引用計數器就加1,當去掉一個引用時,引用計數就減1.當引用計數到零時,該對象的空間就被系統回收。

③retainCount獲取對象的引用計數
④方法:

<1>+alloc(生成對象)【分配內存並且將內存的引用計數置為1】

<2>-retain(持有對象)【引用計數加1】【通常來說,一塊內存有幾個指針指向,引用計數就應該是幾】

<3>-copy【把某一對象的內容拷貝一份,拷貝出新的對象,原有對象的引用計數不變,新的對象的引用計數變1】

<4>-release【引用計數立即減1】/-autorelease【未來的某一時刻引用計數減1】(釋放對象)

【-release:一個指針不再使用這塊內存,就應該release。release完成之後,最好指針置為nil(空)】

 

p1 = nil;// 改變P1指向

 

【-autorelease:通過autoreleasepool自動釋放池,控制autorelease對象的釋放】

<5>-dealloc(銷毀對象)

繼承自父類的方法,當對象引用計數為0的時候,由對象自動調用,銷毀該對象的空間;

// 當對象釋放前會執行該方法
- (void)dealloc{
    NSLog(@"釋放%@",_name);
    // 調用父類中的dealloc
    [super dealloc];// 父類對該方法的實現才是真正的回收空間
}

⑤NSAutoreleasePool(自動釋放池)

<1>方式一:

// 創建自動釋放池
    NSAutoreleasePool *pool1 = [[NSAutoreleasePool alloc] init];
     代碼內容;
// 自動釋放池銷毀
    [pool1 release];

<2>方式二:【自動釋放池使用這種,更安全】

@autoreleasepool { // 創建自動釋放池} // 自動釋放池銷毀

3.內存管理原則

①在一段代碼內,增加和減少的次數要相等

②如果增加的次數大於減少的次數,會造成內存洩露

③如果增加的次數小於減少的次數,會造成內存過度釋放

④如果增加的次數等於減少的次數,還繼續訪問,造成野指針問題

4.協議(Protocol)【一個類可以簽多個協議,用逗號隔開<,>】

①只有.h文件

②接受協議的類實現協議中定義的方法

③實現方法:command+n -> 選擇os x下的source -> Objective-C File -> Next -> File Type(選擇Protocol)

④結構

 

@protocol MyProtocol <NSObject>
//【NSObject可以選擇性刪除,繼承於NSObject】
@required// 方法必須實現(默認)
- (void)eating;
@optional// 可選實現的
- (void)sayHi;
@end

 

5.拷貝

①copy方法

<1>跟retain不同,一個對象想要copy,生成自己的副本,需要服從NSCopying協議,定義copy的細節(如何copy)。如果沒有接受NSCopying協議而給對象發送copy消息,會引起crash

<2>copy方法的實現

  <NSCopying>

<3>copy方法的使用

- (id)copyWithZone:(nullable NSZone *)zone{
//偽拷貝:相當於retain【拷貝地址,引用計數加1】
    return [self retain];

// 淺拷貝:只對對象進行開辟新空間,對象中的屬性公用
//【對象開辟新的空間,但是兩個對象的實例變量指向同一塊空間】
    Person *temp = [[Person allocWithZone:zone] init];
    temp.name = self.name;
    return temp;

// 深拷貝:對對象開辟空間,對象中屬性也開辟空間,然後內容全部復制過去
//【對象開辟新的空間,兩個對象的實例變量也指向不同的空間】
    Person *temp = [[Person allocWithZone:zone] init];
    temp.name = [[NSString alloc] initWithString:self.name];
    return temp;
}

<4>【不是任何對象都可以接收copy消息,只有接受了NSCopying協議的對象才能接收copy消息】

 

八、高級內存管理

1.屬性的語義特性(setter和getter方法優化)

①assign(使用范圍:基本數據類型:char,short,int,float,double)

     @property (nonatomic,assign)NSInteger name;
// ①setter
- (void)setName:(NSString *)name{
    _name = name;
}
// ②getter
- (NSString *)name{
    return _name;
}

②reetain(使用范圍:對象類型)

     @property (nonatomic,retain)NSString *name;
// ①setter
- (void)setName:(NSString *)name{
    if (_name != name) {
        [_name release];
        _name = [name retain];
    }
}
// ②getter
- (NSString *)name{
    // 防止野指針
    return [[_name retain] autorelease];
}

③copy(對象類型,且遵守了<NSCopying>協議)

【如果要對一個對象進行copy,那該對象所屬的類必須遵守<NSCopying>協議】

     @property (nonatomic,copy)NSString *name;
// ①setter
- (void)setName:(NSString *)name{

    if (_name != name) {
        [_name release];
        _name = [name copy];
    }
}
// ②getter
- (NSString *)name{
    // 防止野指針
    return [[_name retain] autorelease];
}

2.dealloc釋放實例變量

①dealloc是NSObject的一個實例方法,用於回收alloc開辟的內存空間 ②在對象引用計數為0是,由系統自動調用

③通常在dealloc中釋放類的實例變量

 

// 重寫銷毀
- (void)dealloc{
    // 在對象銷毀之前,將對象中的實例變量和屬性銷毀
    [_name release];
    [super dealloc];
}

 

④注意:

<1>永遠不要手動調用dealloc

<2>在dealloc方法的最後一行,必須要寫[super dealloc],讓系統真正的去銷毀對象

3.初始化方法【優化】

// 初始化方法
- (instancetype)initWithName:(NSString *)name{
    if (self = [super init]) {
        // 調用setter方法
        // 以後所有方法中給實例方法賦值,都使用setter方法【切記,很重要】
        self.name = name;// 如果不用,可能出現野指針問題
    }
    return self;
}

4.便利構造器的內存管理

①便利構造器,一定配套使用自動釋放池

②所有使用便利構造器創建的對象都不需要釋放

+ (instancetype)personWithName:(NSString *)name{

    Person *p =  [[Person alloc] initWithName:name];
    return  [p autorelease];
}

5.集合的內存管理

①常見的集合類有:NSArray,NSDictionary,NSSet ②集合會自主管理集合內部元素 ③流程 <1>加入集合的元素會被retain <2>移除集合的元素會被release <3>集合被釋放時,會對集合中所有元素release 6.KVC ①KVC:key Value Coding ,鍵值編碼,是一種間接訪問實例變量的方法。 ②KVC提供了一種使用字符串(key)而不是訪問器方法,去訪問一個對象實例變量的機制 ③KVC按順序使用如下技術: <1>檢查是否存在getter方法-<key>或者setter方法-set<key>:的方法 <2>如果沒有上述方法,則檢查時候存在名字為-_<key>、<key>的實例變量 <3>如果仍未找到,則調用valueForUndefinedKey:和setValue:forUndefinedKey:方法。這些方法的默認實現都是拋出異常,可以根據需要重寫。 ④常用方法 <1>
取值
- (id)valueForKey:(NSString *)key;
設置值
- (void)setValue:(id)value forKey:(NSString *)key;
以Person類為例
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end

// 屬性
Person *p = [[Person alloc] init]; p.name = @"張三";
NSLog(@"%@", p.name);

// KVC
Person *p = [[Person alloc] init];
[p setValue:@"張三" forKey:@"name"]; NSLog(@"%@", [p valueForKey:@"name"]);
<2>
獲取鍵值路徑
- (id)valueForKeyPath:(NSString *)keyPath;
設置鍵值路徑
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;
以Person類為例
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *gender;
@end

// 屬性
Person *p = [[Person alloc] init]; p.name = @"張三";
p.gender = @"男";
NSLog(@"%@ %@", p.name, p.gender);

// KVC
Person *p = [[Person alloc] init];
NSDictionary *dic = @[@"name": @"張三", @"gender": @"男"];
[p setValuesForKeysWithDictionary:dic]; NSLog(@"%@ %@", [p valueForKey:@"name"], [p valueForKey:@"gender"]);
<3>
模型類:寫的屬性必須和字典中key值是一樣的【一模一樣】
- (void)setValuesForKeysWithDictionary:(NSDictionary*)keyedValues;
 Student.plist
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <array> <dict> <key>tel</key> <string>11111</string> <key>name</key> <string>Mike</string> <key>age</key> <integer>20</integer> <key>sex</key> <string>男</string> </dict> <dict> <key>tel</key> <string>222222</string> <key>name</key> <string>Joe</string> <key>age</key> <integer>10</integer> <key>sex</key> <string>男</string> </dict> <dict> <key>tel</key> <string>333333</string> <key>name</key> <string>Kitty</string> <key>age</key> <integer>18</integer> <key>sex</key> <string>女</string> </dict> </array> </plist>
 Student.m
 
 #import "Student.h"
 @implementation Student
 // 如果使用KVC賦值,一定重寫這個方法。這個方法可以什麼都不寫。作用防止找不到對應的key而crash【崩潰】
 // 【在解析有大用途】
 - (void)setValue:(id)value forUndefinedKey:(NSString *)key{
 
     // NSLog(@"++=%@ : %@",key,value);
     
 }
 @end
 Student.h
 
 #import <Foundation/Foundation.h>
 // 模型類
 @interface Student : NSObject
 @property (nonatomic,copy)NSString *name;
 @property (nonatomic,retain)NSNumber *age;
 @property (nonatomic,copy)NSString *sex;
 @end
 main.m
 
 #import <Foundation/Foundation.h>
 #import "Student.h"
 int main(int argc, const char * argv[]) {
     
     NSArray *datArray = [NSArray arrayWithContentsOfFile:@"/Users/lanou3g/Desktop/OClesson8練習/OClesson8練習/Student.plist"];
     // 容器(保存對象的數組)
     NSMutableArray *arr = [NSMutableArray array];
     for (NSDictionary *dict in datArray) {
         Student *s = [[Student alloc] init];
         [s setValuesForKeysWithDictionary:dict];
         [arr addObject:s];
     }
     for (Student *stu in arr) {
         NSLog(@"%@ : %@ : %@",stu.name,stu.age,stu.sex);
     }
     
     return 0;
 }

⑤當使用KVC時,如果KVC值和屬性名不一樣時,在類中重寫以下兩個方法:

【在使用KVC賦值時,一定要重寫這個方法,這個方法可以什麼都不寫。作用防止找不到對應的key而崩潰】

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
}
- (id)valueForUndefinedKey:(NSString *)key {
}


7.ARC

①ARC:Automatic Reference Counting,自動引用計數,由開發人員開辟內存空間,但是不需要釋放該內存空間,由系統自動釋放該空間 ②ARC本質上還是基於MRC的,只不過是系統自動添加了釋放內存的方法 ③ARC是編譯器特性 ④從Xcode5.0後,創建的工程默認是開啟ARC的【系統默認ARC】 ⑤當工程開啟ARC後,由於編譯器會自動幫你釋放內存,所有和內存相關操作retain、release、autorelease,都不能寫。【copy可以用】 ⑥重寫dealloc方法時,也不能寫[super dealloc] ⑦屬性語義特性 <1>assign:基本數據類型(char,short,int,float,double) <2>strong:對象類型,相當於MRC中的retain <3>copy:對象類型,且遵守了<NSCopying>協議 <4>weak:對象類型,但是內部不會對對象做retain操作 ⑧ARC和MRC混編 如果需要對特定文件開啟或關閉ARC,可以在工程選項中選擇: Targets -> Compile Phases ->Compile Spurces 在裡面找到對應文件,添加flat <1>打開ARC:-fobjc-arc <2>關閉ARC:-fno-objc-arc
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved