Objective-c學習筆記

OC學習筆記

屬性(property)和成員變量

  • 屬性爲了讓類外能夠訪問成員變量
  • 屬性就是成員變量的外部接口
  • 在類內調用成員變量而不是屬性,屬性是給類外使用的
  • 在新版本的iOS SDK中,只要聲明瞭屬性系統就會自動生成成員變量。
    例如:
@property(nonatomic,strong)NSString *people;

則在類內能夠直接調用成員變量_peopleobjective-c

  • 屬性能夠用點(.)語法調用

方法

  • []調用方法,詳情以下
@interface People : NSObject
 /*
 聲明方法
 - 、+ 是方法的類型,(-表明對象方法(用對象名來調用),+表明類方法(用類名來調用)),
(加號方法和減號方法能夠互相調用,可是須要類名和實例化變量,加號方法不能調用成員變量。)
 */
 - (void)report;
 + (void)report;
 @end

在對象方法中調用類方法,和在類方法中調用對象方法安全

/* .m文件對方法的實現 */
 - (void)report
 {
     NSLog(@"- 號: report");
     [People report1];
 }

 + (void)report1
 {
     NSLog(@"+ 號:report1");
     [[People alloc] report];
 }
  • 對象方法中能夠調用成員變量
  • 初始化方法
//初始化方法
- (id)init;
/* id類型是萬能類型,能夠返回各類類型對象 */
-(instancetype)init;
/* instancetype表明當前類的類型 */

對於選擇哪一個,在初始化方法中都行,對於其餘的一些方法,填id會致使錯誤,通常填寫instancetype。app

關於id和instancetype

以下代碼框架

@interface NSArray
  + (id) creatAnArray;
@end

當咱們用以下方式初始化NSArray時:函數

[NSArray creatAnArray]; 性能

獲得的返回類型將和方法聲明的返回類型同樣,是id;學習

但當咱們將id改成instancetype時:atom

@interface NSArray
+ (instancetype) creatAnArray;
@end

再用剛一樣的方式初始化時:指針

[NSArray creatAnArray];code

獲得的返回類型將會和方法所在類的類型相同,是NSArray*;

id和instancetype的區別

  1. id在編譯的時候不能判斷對象的真實類型

    instancetype在編譯的時候能夠判斷對象的真實類型

  2. 若是init方法的返回值是instancetype,那麼將返回值賦值給一個其它的對象會報一個警告

    若是是在之前, init的返回值是id,那麼將init返回的對象地址賦值給其它對象是不會報錯的

  3. id能夠用來定義變量, 能夠做爲返回值, 能夠做爲形參

    instancetype只能用於做爲返回值,例如:

    //err,expected a type

{

//do something

}

就是錯的,應該寫成:

  • (void)setValue:(id)value

{

//do something

}

**參考自[iOS instancetype 和 id 區別詳解](https://juejin.im/entry/588022572f301e00697c8756)**

## 封裝

- 修飾符的問題

@interface MyClass : NSObject
{

//成員變量訪問修飾符的問題
//默認 - 受保護

//公有 - 在類內類外均可以使用
@public
int _classInt;  /*聲明爲公有成員類型,則在類外也能夠被調用,可是要用指向(->)調用*/

//私有 - 在類內可使用,類外沒法調用而且不能被繼承
@private

//受保護 - 在類內可使用,類外沒法調用而且能夠被繼承
@protected

//框架權限 - 在框架內至關於受保護,在框架外至關於私有
@package

}
@property(nonatomic,strong)NSString *className;
//方法是沒有訪問修飾符的同C語言同樣

  • (void)report;

@end

## 繼承

- OC中沒有多繼承,要實現多繼承要經過協議來實現。
- 父類中的私有成員變量是沒法繼承使用的,而若是子類繼承了父類的方法,方法中有隊私有變量的操做以及打印,那咱們是能夠看到的,可是咱們不能夠在子類中直接調用私有變量。
- 若是父類中的方法沒有寫聲明則子類沒法繼承父類中對應的方法。

## 多態

- OC中不支持方法的重載

## 註釋

- 使用 /\*\* 文本 **/ 的註釋格式(快捷鍵cmd+alt+/)能夠對方法等進行快速註釋。

## 修飾符

在蘋果引入ARC以後,修飾符有所增長

### 存取類型

1. 任何屬性均可以聲明爲readwrite或readonly,且默認設置爲readwrite
2. readwrite:程序自動建立setter/getter方法。
3. readonly:程序之建立getter方法。
4. 自定義setter/getter方法 : @propery(setter=setId,getter=getId) int id; 

### 原子性

1. atomic:生成的setter/getter操做爲原子性的操做,執行性能較低(系統默認)。
2. noatomic:生成的setter/getter操做爲非原子性的操做,執行性能較高。通常推薦手動設置爲該屬性。

### 生命週期

#### MRC

1. assign: 簡單賦值,不更改引用計數。通常用於基礎類型的數據(NSInteger)和C語言類型數(int,float,double,char,bool)。是MRC模式下的默認值。
2. copy: 會拷貝傳入的對象(即建立一個引用計數爲1的新對象,可是內容與傳入對象相同),並把新對象賦值給實例變量。經常使用與NSString,NSArray,NSDictionary,NSSet等。
3. retain: 釋放舊對象,並使傳入的新對象引用計數+1。此屬性只能用於NSObject及其子類,而不能用於Core Foundation(由於其沒有使用引用計數,須要另外使用CFRetain和CFRelease愛進行CF的內存管理)。

#### ARC

ARC中加入如下修飾符

1. strong: 強引用,相似於retain。要求保留傳入的對象,並放棄原有對象。一個對象只要被至少一個強引用指向,則其不會被釋放,而當沒有強引用指向時則會被釋放。在ARC下是對象類型的默認值。

2. weak: 弱引用,要求不保留傳入的屬性(既不會使傳入的對象引用計數+1)。相似於assign,但與assign不一樣的是,當它們指向的對象被釋放後,weak會被自動置爲nil,而assign則不會,因此assign會致使「野指針」的出現,weak能夠避免懸空指針。

3. unsafe_unretained: 其實質等同於assign。與weak的區別就是指向的對象若是被釋放,其不會被置爲nil,而致使懸空指針的出現。它是ARC模式下非對象屬性的默認值。

   ​

#### 屬性的默認值

- MRC:(atomic, readwrite, assign)
- ARC下對象類型屬性:(atomic, readwrite, strong)
- ARC下非對象類型:(atomic, readwrite, unsafe_unretained)

### 關於copy和strong

- **使用`copy`修飾immutable類型,使用`strong`修飾mutable類型**

引用一下一句話:

> For attributes whose type is an immutable value class that conforms 
>
> to the `NSCopying` protocol, you almost always should specify `copy`
>
> in your `@property` declaration. Specifying retain is something you 
>
> almost never want in such a situation.

舉個例子:

@interface UserInfo : NSObject <NSCopying>

@property (nonatomic, copy) NSString *firstName;
@property (nonatomic, strong) NSString *lastName;

@end

//main 函數中
NSMutableString *mutableFirstName = [NSMutableString stringWithFormat:@"張"];
NSMutableString *mutableLastName = [NSMutableString stringWithFormat:@"全蛋"];

UserInfo *my = [[UserInfo alloc] init];
my.firstName = mutableFirstName;
my.lastName = mutableLastName;
NSLog(@"全名:%@%@", my.firstName, my.lastName);
// print: 全名:張全蛋

// 改mutableFirstName 張 爲 李
[mutableFirstName deleteCharactersInRange:NSMakeRange(0, 1)];
[mutableFirstName appendString:@"李"];
// 改mutableLastName 全蛋 爲 沒蛋
[mutableLastName appendString:@"沒蛋"];
NSLog(@"全名:%@%@", my.firstName, my.lastName);
// print: 全名:張沒蛋

對於immutable對象類型屬性,假設該類型存在mutable版本,若使用`strong`修飾該屬性,則將會是不安全的。好比在上述例子中,`my.firstName`被`copy`修飾,而`my.lastName`被`strong`修飾,當把mutable類型賦給了immutable類型(即`NSMutableString`賦給`NSString`),以後又修改mutable類型變量的值(將張改成李,全蛋改成沒蛋),`copy`修飾的`firstName`不會改變,而`strong`修飾的`lastName`會隨之改變。這是不但願發生的。

對於二者的setter方法的定義以下:
  • (void) setFirstName:(NSString*)firstName{
    _firstName = [firstName copy];

}

  • (void) setLastName:(NSString*)lastName{
    _lastName = lastName;

}

若是去掉copy,寫成下面這個樣子,則copy的好處將不復存在。
  • (void) setFirstName:(NSString*)firstName{
    _firstName = [firstName copy];

}

- 不是全部遵循`NSCopying`類型屬性都應該使用`copy`修飾,而是對於`NSString`、`NSDictionary`等屬性才須要使用`copy`修飾,由於它們存在mutable版本,在爲屬性賦值時,右值極可能是它們的mutable類型對象,若使用`strong`修飾則會帶來不穩定因子;另一個方面,若是屬性類型不存在對應的mutable版本,則徹底不用擔憂這點,反正你也沒法在外部修改它,不穩定因子天然不存在了。(參考[Objective-C copy那些事兒](http://zhangbuhuai.com/copy-in-objective-c/))
- mutable屬性類型不能用`copy`修飾,被修飾符`copy`修飾的屬性,默認的setter賦值方式是`_iVar = [var copy];`而`copy`方法返回的是immutable類型,將immutable對象賦值給mutable類型指針顯然是不對的。

## 內存管理法則
相關文章
相關標籤/搜索