藍懿ios技術交流和心得分享16.1.17

1.UIControlEventTouchDown

單點觸摸按下事件:用戶點觸屏幕,或者又有新手指落下的時候。

2.UIControlEventTouchDownRepeat

多點觸摸按下事件,點觸計數大於1:用戶按下第二、三、或第四根手指的時候。

3.UIControlEventTouchDragInside

當一次觸摸在控件窗口內拖動時。

4.UIControlEventTouchDragOutside

當一次觸摸在控件窗口之外拖動時。

5.UIControlEventTouchDragEnter

當一次觸摸從控件窗口之外拖動到內部時。

6.UIControlEventTouchDragExit

當一次觸摸從控件窗口內部拖動到外部時。

7.UIControlEventTouchUpInside

所有在控件之內觸摸擡起事件。

8.UIControlEventTouchUpOutside

所有在控件之外觸摸擡起事件(點觸必須開始與控件內部纔會發送通知)。

9.UIControlEventTouchCancel

所有觸摸取消事件,即一次觸摸因爲放上了太多手指而被取消,或者被上鎖或者電話呼叫打斷。

10.UIControlEventTouchChanged

當控件的值發生改變時,發送通知。用於滑塊、分段控件、以及其他取值的控件。你可以配置滑塊控件何時發送通知,在滑塊被放下時發送,或者在被拖動時發送。

11.UIControlEventEditingDidBegin

當文本控件中開始編輯時發送通知。

12.UIControlEventEditingChanged

當文本控件中的文本被改變時發送通知。

13.UIControlEventEditingDidEnd

當文本控件中編輯結束時發送通知。

14.UIControlEventEditingDidOnExit

當文本控件內通過按下回車鍵(或等價行爲)結束編輯時,發送通知。

15.UIControlEventAlltouchEvents

通知所有觸摸事件。

16.UIControlEventAllEditingEvents

通知所有關於文本編輯的事件。

17.UIControlEventAllEvents

通知所有事件

一、明確兩點

1.Block可以訪問Block函數以及語法作用域以內的外部變量。也就是說:一個函數裏定義了一個block,這個block可以訪問該函數的內部變量(當然還包括靜態,全局變量),即block可以使用和本身定義範圍相同的變量。

2.Block其實是特殊的Objective-C對象,可以使用copy、release等來管理內存,但和一般的NSObject的管理方式有些不同,稍後會說明。

二、Block語法

Block很像函數指針,這從Block的語法上就可以看出。

Block的原型:

返回值 (^名稱)(參數列表)

Block的定義

^ 返回值類型 (參數列表) { 表達式 }

其中返回值類型和參數列表都可以省略,最簡單的Block就是:

^{ ; };

一般的定義就是:

返回值 (^名稱)(參數列表) = ^(參數列表){代碼段};

爲了方便通常使用typedef定義:

typedef void (^blk) (void);

三、Block存儲域

Block能夠截獲自動變量,自動變量的當前值會被拷貝到棧上作爲常量,此時不能在Block內對自動變量進行賦值操作,如果有這種需求,則需要該變量是:

1.靜態變量

2.全局變量

3.或者使用__block修飾符

根據Block中是否引用了自動變量,可以將Block存儲區域分類:

1.__NSStackBlock__存儲在棧上

2.__NSGlobalBlock__存儲在全局數據區域(和全局變量一樣)

3.__NSMallocBlock__存儲在堆上

沒有引用自動變量或者在全局作用域的Block爲__NSGlobalBlock__,其他的基本上都是__NSStackBlock__。對__NSStackBlock__執行copy操作會生成__NSMallocBlock__。

一般來說出問題的Block大部分都是__NSStackBlock__,超過了__NSStackBlock__的作用域__NSStackBlock__就會銷燬。

四、對Block執行retain,copy方法的效果

Block是C語言的擴展,C語法也可以使用Block的語法,對應的C語言使用Block_copy、Block_release。

無論是__NSStackBlock__,還是__NSGlobalBlock__,執行retain都不起作用。而__NSMallocBlock__執行retain引用計數+1。

對於copy操作,__NSStackBlock__會被複制到堆上得到一份新的__NSMallocBlock__,__NSStackBlock__還是存在的,而__NSGlobalBlock__執行copy操作不起作用。而對__NSMallocBlock__執行copy操作會引起引用計數加1。

五、什麼時候要對__NSStackBlock__執行copy操作?

配置在棧上的Block也就是__NSStackBlock__類型的Block,如果其所屬的變量作用域結束該Block就會廢棄。這個時候如果繼續使用該Block,就應該使用copy方法,將__NSStackBlock__拷貝爲__NSMallocBlock__。當__NSMallocBlock__的引用計數變爲0,該__NSMallocBlock__就會被釋放。

如果是非ARC環境,需要顯式的執行copy或者antorelease方法。

而當ARC有效的時候,實際上大部分情況下編譯器已經爲我們做好了,自動的將Block從棧上覆制到堆上。包括以下幾個情況:

1.Block作爲返回值時,類似在非ARC的時候,對返回值Block執行[[returnedBlock copy] autorelease];

2.方法的參數中傳遞Block時

3.Cocoa框架中方法名中還有useringBlock等時

4.GCD相關的一系列API傳遞Block時

比如:[mutableAarry addObject:stackBlock];這段代碼在非ARC環境下肯定有問題,而在ARC環境下方法參數中傳遞__NSStackBlock__會自動執行copy,所以就不會出現問題。

六、Block的循環引用

對於非ARC下,爲了防止循環引用,我們使用__block來修飾在Block中使用的對象。

對於ARC下,爲了防止循環引用,我們使用__weak來修飾在Block中使用的對象。

原理就是:ARC中,Block中如果引用了__strong修飾符的自動變量,則相當於Block對該對象的引用計數+1。

七、代碼驗證

驗證__NSStackBlock__

我們往可變數組中添加一個__NSStackBlock__。

在MRC環境下,__NSStackBlock__在自身作用域結束後就從棧中釋放,所以我們再次使用它的時候,程序就會發生崩潰。

在ARC環境下,編譯器會自動對__NSStackBlock__執行copy,拷貝一份到堆上生成一個新的__NSMallocBlock__,我們再次使用它的時候,程序正常運行

 


棧(stack):由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。

堆(heap): 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式類似於鏈表。

全局區(靜態區static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域,程序結束後由系統釋放。

文字常量區:常量字符串放在這裏, 程序結束後由系統釋放

程序代碼區:存放函數體的二進制代碼。

程序示例

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 0;//全局初始化區
char *p1;//全局未初始化區
main()
    {
        intb;//棧
        chars[]= "abc";//棧
        char*p2;//棧
        char*p3= "123456";//123456\0在常量區,p3在棧上。
        staticint c =0//全局(靜態)初始化區
        p1= (char*)malloc(10);
        p2= (char*)malloc(20);
        //分配得來得10和20字節的區域就在堆區。
        strcpy(p1,"123456");//123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}

 

Block基本語法

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//As a local variable:
returnType (^blockName)(parameterTypes)= ^returnType(parameters){...};
As a property:
 
//As a property:
@property(nonatomic,copy)returnType (^blockName)(parameterTypes);
As a method parameter:
 
//As a method parameter:
- (void)someMethodThatTakesABlock:(returnType(^)(parameterTypes))blockName;
As an argument to a method call:
 
//As an argument to a method call:
[someObjectsomeMethodThatTakesABlock:^returnType(parameters){...}];
As a typedef:
 
//As a typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters){...};

 

修飾Block的成員變量

Block 成員需要使用 copy 進行修飾,需要考慮Block是否線程安全,必要情況下使用atomic參數,當使用atomic參數也不能百分百確保線程安全,因此在使用時最好將block屬性賦值給本地變量在使用,以防止其它線程將self.block置空。實際上,我們使用修飾符 copy 是因爲將存在棧區上的block轉移到堆區上,這個習慣是在MRC下的,現在在ARC下使用 copy 和 strong 是相同的。

解決self循環引用的問題(ARC)

1
__weak __typeof(self)weakSelf = self;

 

AFNetworking的使用技巧

 

1
2
3
4
5
6
7
8
9
10
MyObject *obj= [[MyObjectalloc]init];
obj.text= @"string";
__weak MyObject *weakObj= obj;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
    __strongMyObject *strongObj= weakObj;
    sleep(3);
});
sleep(1);
obj = nil;
sleep(4);

把變量在 block 外先用 __weak 聲明,在 block 內把前面 __weak 聲明的變量在賦值給 __strong 修飾的變量。這種寫法的好處就是可以讓變量在 block 內部安全使用,即使外部對象釋放了,也會在 block 的生命週期內保留該變量。這種寫法非常巧妙,既避免了循環引用的問題,又可以在 block 內部持有該變量。

棧(stack):由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。

堆(heap): 一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS回收 。注意它與數據結構中的堆是兩回事,分配方式類似於鏈表。

全局區(靜態區static):全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域, 未初始化的全局變量和未初始化的靜態變量在相鄰的另一塊區域,程序結束後由系統釋放。

文字常量區:常量字符串放在這裏, 程序結束後由系統釋放

程序代碼區:存放函數體的二進制代碼。

程序示例

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int a = 0;//全局初始化區
char *p1;//全局未初始化區
main()
    {
        intb;//棧
        chars[]= "abc";//棧
        char*p2;//棧
        char*p3= "123456";//123456\0在常量區,p3在棧上。
        staticint c =0//全局(靜態)初始化區
        p1= (char*)malloc(10);
        p2= (char*)malloc(20);
        //分配得來得10和20字節的區域就在堆區。
        strcpy(p1,"123456");//123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}

 

Block基本語法

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//As a local variable:
returnType (^blockName)(parameterTypes)= ^returnType(parameters){...};
As a property:
 
//As a property:
@property(nonatomic,copy)returnType (^blockName)(parameterTypes);
As a method parameter:
 
//As a method parameter:
- (void)someMethodThatTakesABlock:(returnType(^)(parameterTypes))blockName;
As an argument to a method call:
 
//As an argument to a method call:
[someObjectsomeMethodThatTakesABlock:^returnType(parameters){...}];
As a typedef:
 
//As a typedef:
typedef returnType (^TypeName)(parameterTypes);
TypeName blockName = ^returnType(parameters){...};

 

修飾Block的成員變量

Block 成員需要使用 copy 進行修飾,需要考慮Block是否線程安全,必要情況下使用atomic參數,當使用atomic參數也不能百分百確保線程安全,因此在使用時最好將block屬性賦值給本地變量在使用,以防止其它線程將self.block置空。實際上,我們使用修飾符 copy 是因爲將存在棧區上的block轉移到堆區上,這個習慣是在MRC下的,現在在ARC下使用 copy 和 strong 是相同的。

解決self循環引用的問題(ARC)

1
__weak __typeof(self)weakSelf = self;

 

AFNetworking的使用技巧

 

1
2
3
4
5
6
7
8
9
10
MyObject *obj= [[MyObjectalloc]init];
obj.text= @"string";
__weak MyObject *weakObj= obj;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
    __strongMyObject *strongObj= weakObj;
    sleep(3);
});
sleep(1);
obj = nil;
sleep(4);

把變量在 block 外先用 __weak 聲明,在 block 內把前面 __weak 聲明的變量在賦值給 __strong 修飾的變量。這種寫法的好處就是可以讓變量在 block 內部安全使用,即使外部對象釋放了,也會在 block 的生命週期內保留該變量。這種寫法非常巧妙,既避免了循環引用的問題,又可以在 block 內部持有該變量。

  • 學習ios  重要還是要理清楚思路  在做或者看老師代碼的時候 自己多想想爲什麼  不要自己看着就抄       另外還是要推薦一下 藍懿IOS這個培訓機構  和劉國斌老師劉國斌老師還是很有名氣的,聽朋友說劉老師成立了藍懿iOS,,老師講課方式很獨特,能夠儘量讓每個人都能弄明白,有的比較難懂的地方,如果有的地方還是不懂得話,老師會換個其它方法再講解,這對於我們這些學習iOS的同學是非常好的,多種方式的講解會理解得更全面,這個必須得給個贊,嘻嘻,還有就是這裏的學習環境很好,很安靜,可以很安心的學習,安靜的環境是學習的基礎,小班講課,每個班20幾個學生,學習氛圍非常好,每天都學到9點多才離開教室,練習的時間很充裕,而且如果在練習的過程中有什麼困難,隨時可以向老師求助,不像其它機構,通過視頻教學,有的甚至學完之後都看不到講師本人,問點問題都不方便,這就是藍懿與其它機構的區別,相信在劉國斌老師的細心指導下,每個藍懿學員都能找到滿意的工作,加油!

                                                                      寫博客第九十九天;

                                                                                  QQ:565803433

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