OC總結篇 - OC基礎

變量 - 屬性關鍵字 - 初始化方法 - 分類與擴展 - 關聯(lián)對象 - 代理和通知 - 多繼承 - 異步 - 控制臺

變量
<--成員變量,實例變量,屬性變量的區(qū)別-->
成員變量 - interface括號中的全部都是成員變量(包含了實例變量,但實例變量也是成員變量的一種)
實例變量 - 是一種特殊的成員變量,用Class類實例化出來的對象就是實例變量,例如 UIButton *btn
屬性變量 - 自動生成setter和getter,沒有匹配成員變量的屬性,會自動創(chuàng)建一個帶下劃線的成員變量
<--其他變量-->
在方法之外定義的
全局變量 - int var = 4
靜態(tài)全局變量 - static int var = 4

在方法內部定義的
局部變量 - int var = 1
局部靜態(tài)變量 - static int var = 1
屬性關鍵字

@property (nonatomic,strong) NSMutableArray * dataArray;
1.讀寫權限 readwrite / readonly
2.原子性,也就是是否線程安全(atomic和nonatomic)
3.內存管理(引用計數(shù)方案)
默認修飾符
1.基本數(shù)據(jù)類型:atomic readwrite assign
2.普通OC對象: atomic readwrite strong

建議property最好是數(shù)據(jù),不要是控件,控件建議寫成私有的,在使用時我們進行數(shù)據(jù)傳遞,然后更新視圖控件

readwrite: 生成getter和setter方法
readonly: 只生成getter方法
  atomic - 一個屬性可能會被兩個及以上線程同時訪問,若使用這個屬性,編譯器會自動為變量加鎖,保證線程安全
           可以保證對該成員變量的賦值和獲取數(shù)據(jù)是線程安全的
           如果我們用atomic修飾了一個數(shù)組,那么對這個數(shù)組進行賦值和獲取,是可以保證線程安全的
           但如果我們對數(shù)組進行操作,添加或移除對象,那么是不在atomic的負責范圍內,所以是沒有辦法保證線程安全的
  nonatomic - 不加鎖,不能保證線程安全,但是訪問速度快
`引用計數(shù)`
引用計數(shù)有以下幾個修飾
assign、weak、strong、 copy (ARC) 
assign、retain、release (MRC此處不再討論)


如何使用
assign: 基礎數(shù)據(jù)類型(NSInteger,float,double,CGFloat,BOOL)
weak:   代理
strong: 可變類型的屬性(NSMutableArray,NSMutableDictionary,NSMutableString)
        控件
        對象
copy:    不可變類型的屬性(NSArray,NSDictionary,NSString)
             block


下面分類講解
*  assign / weak

*  assign - 修飾基本數(shù)據(jù)類型,如int, BOOL等
          - 修飾對象類型時,不改變其引用計數(shù)
          - 會產生懸垂指針,assign所修飾的對象,在被釋放之后,assign指針仍指向原對象內存地址,如果這時通過assign指針,繼續(xù)訪問原對象,會導致內存泄露或程序異常

*  weak   - 不改變被修飾對象的引用計數(shù),一般使用weak是用來解決循環(huán)引用問題
          - 所修飾的對象在被釋放之后會自動置為nil

*  在修飾對象時,weak和assign都不改變被修飾對象的引用計數(shù)
*  weak可以修飾對象,assign既可以修飾對象,也可以修飾基本數(shù)據(jù)類型
*  weak所修飾的對象,在被廢棄之后,weak指針置為nil. assign所修飾的對象,在被釋放之后,assign指針仍指向原對象內存地址

------------------------------------------------------------

strong(ARC) / return(MRC) - 這兩個關鍵字都是用來修飾對象

------------------------------------------------------------
copy

淺拷貝 = 指針拷貝,會增加被拷貝對象的引用計數(shù),并沒有發(fā)生新的內存分配,兩個指針指向同一塊原來的內存空間
深拷貝 = 內存拷貝,不會增加被拷貝對象的引用計數(shù),因為沒有新指針指向原來的內存空間,產生了新的內存分配,出現(xiàn)了兩塊內存

可變對象的copy和mutableCopy都是深拷貝
不可變對象的copy是淺拷貝,mutableCopy是深拷貝
copy方法返回的都是不可變對象,若被拷貝對象是可變對象,返回的也是不可變對象

問題??
NSMutableArray用copy修飾會出現(xiàn)什么問題?
程序異常,因為copy之后就變成不可變了,在進行增刪改操作,會崩潰

通過上面我們知道了為什么可變對象不能用copy只能用strong,那么為什么不可變對象必須要用copy呢?
知道多態(tài)的,都知道父類指針可以指向子類對象,那么使用 copy 的目的是為了讓本對象的屬性不受外界影響
??
NSString的子類是NSMutableString
如果用strong聲明一個string,然后將NSMutableString賦值給string,那么當NSMutableString的值變化的時候,NSString值也會變化,所以要用copy限制它的值不受外界影響

屬性備注

ivar+set/get
如果不自己實現(xiàn)set和get方法,系統(tǒng)會幫我們合成
當我們聲明一個屬性的時候,系統(tǒng)在底層幫我們合成的set/get方法,在底層調用時有什么區(qū)別

初始化方法
1. alloc - 繼承NSObject的對象的創(chuàng)建和分配內存
2. init - 是種工廠模式
          直接繼承與NSObject的對象里面什么也沒干,返回方法的調用者
          但是Foundation框架里面的NSArarry和NSDic的init做了很多事情
          之所以有init, 是特意讓我們來重寫的,也就是自己初始化
分類
"***作用***"
1.聲明私有方法 - 把分類的頭文件放到類的.m中,就滿足了類既能使用這個方法,又對外不暴露
2.分解體積龐大的類文件
3.把Framework的私有方法公開

"***特點***"
1.在運行時進行決議 
  - 在編寫完分類文件之后,并沒有把分類中添加的內容附加到類上,而是在運行時通過runtime把分類內容真實的添加到類上
2.可以為系統(tǒng)類添加分類
<--分類結構體-->
可添加
1.實例方法
2.類方法
3.協(xié)議
4.實例屬性(只聲明了對應的get和set方法,但沒有在分類中添加上相應的實例變量)
5.可以通過關聯(lián)對象來為分類添加實例變量
<--源碼分析-->
分析分類添加實例方法的邏輯如上圖
1.倒敘遍歷分類,最先訪問最后編譯的分類,獲取該分類的方法列表,最后編譯的分類方法列表最先被添加到分類方法數(shù)組中
2.然后將分類方法數(shù)組拼接到宿主類上
"重要總結??"
分類實現(xiàn)原理由運行時決議,不同分類中含有同名分類方法,誰最終生效,取決于誰最后參與編譯
假如分類中添加的方法恰好是宿主類中的同名方法,分類方法會"覆蓋"同名的宿主類方法
(消息傳遞過程中會優(yōu)先查找數(shù)組靠前的元素,若找到了就會調用,但宿主類的同名方法仍然存在)

1. 分類添加的同名方法可以"覆蓋"原宿主類方法
   -在我們消息發(fā)送過程中,是根據(jù)選擇器名稱來查找的,一旦查找到對應的實現(xiàn)就會返回
   -由于分類方法位于數(shù)組靠前的位置,若分類和宿主類方法重名,會先查找到分類的方法

2. 最后編譯的分類同名方法才會最終生效,其他分類都會被覆蓋掉
   -若我們添加兩個分類,兩個分類中都有同名方法,哪個會生效,取決于分類的編譯順序
   -因為是倒序編譯,最后編譯的分類同名方法才會最終生效,其他都會被覆蓋掉

3. 名字相同的分類會引起編譯報錯
   -因為在生成具體分類的時候,經過runtime在編譯過程中會把我們添加的分類名字以下劃線方式拼接到宿主類上
   -如果名字相同,就會類似于我們定義了兩個同名變量,會引起編譯報錯
擴展

只以聲明的形式存在,沒有具體實現(xiàn),多數(shù)情況寄生于宿主類的.m中,也就是說,它不是獨立存在實現(xiàn)的一個文件
在開發(fā)時,一般把擴展的聲明放到宿主類的.m文件之中

"***作用***"
1.聲明私有屬性,是可以不對子類暴露的
2.聲明私有方法,方便閱讀
3.聲明私有成員變量

"***特點***"
1.編譯時決議
2.不能為系統(tǒng)類添加擴展
3.類的一個內部的私有聲明
關聯(lián)對象
"關聯(lián)對象是什么"
AssociationsManager - AssociationsHashMap( key - Value )

所有類的關聯(lián)對象都放在同一個全局容器中
關聯(lián)對象是由系統(tǒng)提供的,由AssociationsManager類來管理
這個類有一個成員變量叫做AssociationsHashMap,我們創(chuàng)建的每一對象的關聯(lián)對象,都存儲在AssociationsHashMap里,它是個全局容器,,通過hash來實現(xiàn)的一個map
<--關聯(lián)對象怎么使用-->
1.添加關聯(lián)對象
void objc_setAssociatedObject(ocject對象,key,value,策略)
object是準備被關聯(lián)的對象,key是我們要g關聯(lián)的值得標識,value是要關聯(lián)的值,policy是要通過哪種策略(copy,return或assign)將keyvalue關聯(lián)到對象上

2.取關聯(lián)對象的值
id objc_getAssociatedObject(object對象,key)

3.移除關聯(lián)對象
void  objc_removeAssociatedObjects(object對象)
<--關聯(lián)對象是如何實現(xiàn)的-->

代理和通知
@protocol
1.一對一
2.一般聲明為weak避免循環(huán)引用
3.代理模式實現(xiàn)

NSNotification
1.一對多
2.是使用觀察者模式來實現(xiàn)的,用于跨層傳遞消息的機制
3.觀察者模式實現(xiàn)

代理是一種軟件設計模式,也就是代理模式
在iOS中,以@protocol形式體現(xiàn)
傳遞方式是一對一

代理的工作流程

委托方把要求代理方實現(xiàn)的接口全都放在協(xié)議中
協(xié)議中可以聲明屬性或者方法
然后由代理方進行具體的實現(xiàn)

代理方和委托方是以什么樣的關系實現(xiàn)的
通知
  1. 傳遞方式是一對多
  2. 是使用觀察者模式來實現(xiàn)的,用于跨層傳遞消息的機制
    在業(yè)務開發(fā)過程中,涉及到數(shù)據(jù)層,網(wǎng)絡層,業(yè)務邏輯層和UI層,一般的處理邏輯是需要由網(wǎng)絡層傳遞給數(shù)據(jù)層,然后經過業(yè)務邏輯層加工,再去更新UI
    有些時候,可能需要網(wǎng)絡層返回的數(shù)據(jù),不經過業(yè)務邏輯層,直接到UI層,就會涉及到所謂的跨層傳遞
代理和通知的區(qū)別
  1. 代理是由代理模式實現(xiàn)的,通知是由觀察者模式實現(xiàn)的
  2. 代理傳遞方式是一對一,通知傳遞方式是一對多
一對多
1.聲明消息
[[NSNotificationCenter defaultCenter] addObserver:self
                                    selector:@selector(respondNotification:) name:@“FQNotification" object:nil];

2.響應消息
[[NSNotificationCenter defaultCenter] postNotificationName:@“FQNotification”object:@“l(fā)lama"];

3.實現(xiàn)消息
- (void)respondNotification:(NSNotification*)aNotification
    {
       NSString *number= [aNotification object];
      NSLog(@"接收到的內容是%@",number);
    }

怎么實現(xiàn)通知機制

NS開頭的文件沒有源代碼,所以不知道具體實現(xiàn)
假如讓自己實現(xiàn)一個通知機制,會如何設計


在通知中心,也就是NSNotificationCenter這個系統(tǒng)類中,可能內部會維護一個map表,這里面的key就是NotificationName,value就是我們添加的observers,對同一個NotificationName可能添加多個observers,所以observers_List應該是一個數(shù)組列表.列表中的每個成員,都要包含通知接收的觀察者,還要觀察這個觀察者調用的方法

KVO和通知的區(qū)別:
1.都是一對多
2.但是KVO只能監(jiān)聽屬性(set變化),通知監(jiān)聽沒有局限性
3.KVO是被觀察者發(fā)出變化通知,觀察者直接響應.但通知是被觀察發(fā)出變化通知,由通知中心統(tǒng)一發(fā)出,然后觀察者才響應,多了一步

多繼承
ClassA實現(xiàn)了A方法,ClassB實現(xiàn)了B方法,ClassC即想實現(xiàn)A方法也想實現(xiàn)B方法,C++中用多繼承就可以實現(xiàn),但OC中沒有
OC不支持多繼承,但可以有多種方式模擬出多繼承實現(xiàn)
1.Runtime的消息轉發(fā)機制
2.協(xié)議protocol支持多繼承
  ClassC遵循ClassA和ClassB的協(xié)議即可實現(xiàn)這兩個類的協(xié)議方法
異步
1. 多線程,異步加載數(shù)據(jù)
    讓子線程去處理耗時操作的代碼塊,再回到主線程刷新
    ```
        __weak typeof(self) weakSelf = self;

        dispatch_async(dispatch_get_global_queue(0, 0), ^{

            // 處理耗時操作的代碼塊...

            UIImageView *imgView = weakSelf.imgViewArray[i];

            UIImage *img = [UIImage imageNamed:dataArray[i]];

            //通知主線程刷新

            dispatch_async(dispatch_get_main_queue(), ^{

                imgView.image = img;

            });

        });
    ```
2. YYTransaction,異步繪制 (不會用)
3. 用Runloop來實現(xiàn)異步
    監(jiān)聽Runloop的空閑狀態(tài),在Runloop即將休眠時(空閑時)再去繪制圖片
控制臺
po
bt(打斷點,然后bt,會出現(xiàn)調用順序)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,621評論 1 32
  • 1.設計模式是什么? 你知道哪些設計模式,并簡要敘述?設計模式是一種編碼經驗,就是用比較成熟的邏輯去處理某一種類型...
    龍飝閱讀 2,294評論 0 12
  • 一、分類(Category) 問題1:你用分類都做了哪些事情? 聲明私有方法 分解體積龐大的類文件 把Framew...
    huoshe2019閱讀 806評論 0 2
  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,800評論 0 11
  • 春風拂面 春草依依 高大的白楊枝葉茂密 翠綠的麥苗剛剛出穗 走在家鄉(xiāng)春天的路上 頑皮的孩子不停奔跑 享受著家鄉(xiāng)春天...
    1如是我聞閱讀 1,453評論 16 50

友情鏈接更多精彩內容