addTarget: action: forControlEvents:在我們開(kāi)發(fā)中最為經(jīng)常用的方法,尤其是UIButton。這個(gè)方法的最底層為UIControl類,在我們開(kāi)發(fā)中用到它的,都是它子類。
UIControl類
UIControl是控件類的基類,它是一個(gè)抽象基類,我們不能直接使用UIControl類來(lái)實(shí)例化控件,它只是為控件子類定義一些通用的接口,并提供一些基礎(chǔ)實(shí)現(xiàn),以在事件發(fā)生時(shí),預(yù)處理這些消息并將它們發(fā)送到指定目標(biāo)對(duì)象上。
UIControl的是針對(duì)單點(diǎn)觸摸,由于UIControl本身是視圖,所以它實(shí)際上也繼承了UIResponse。
為了判斷當(dāng)前對(duì)象是否正在追蹤觸摸操作,UIControl定義了一個(gè)tracking屬性。該值如果為YES,則表明正在追蹤。這對(duì)于我們是更加方便了,不需要自己再去額外定義一個(gè)變量來(lái)做處理。
UIControl的其它具體屬性和特性可以觀看這篇文章:http://www.cocoachina.com/ios/20160111/14932.html
這里主要說(shuō)一下UIControl的Target-Action機(jī)制
Target-action是一種設(shè)計(jì)模式,直譯過(guò)來(lái)就是目標(biāo)-行為。當(dāng)我們通過(guò)代碼為一個(gè)按鈕添加一個(gè)點(diǎn)擊事件時(shí),通常是如下處理:
[button addTarget:self action:@selector(tapButton:) forControlEvents:UIControlEventTouchUpInside];
也就是說(shuō),當(dāng)按鈕的點(diǎn)擊事件發(fā)生時(shí),會(huì)將消息發(fā)送到target(此處即為self對(duì)象),并由target對(duì)象的tapButton:方法來(lái)處理相應(yīng)的事件。這里的target的對(duì)象是一個(gè)在內(nèi)存中的,tapButton:的執(zhí)行方法也是對(duì)象還存在。如果這兩者不存在會(huì)出現(xiàn)崩潰現(xiàn)象。
例子:
我創(chuàng)建一個(gè)對(duì)象A是繼承NSObject,在這個(gè)對(duì)象中寫(xiě)一個(gè)方法用來(lái)做執(zhí)行的。這是我在UIControl分類B的一個(gè)方法中創(chuàng)建A,接著寫(xiě)Target-action,tapButton:的方法是A對(duì)象中方法。所有的都準(zhǔn)備好了,執(zhí)行的時(shí)候出現(xiàn)了崩潰。
代碼:
- (void)clickOperation:(void (^) (void))perform style:(UIControlEvents)style {
TYImplementCallback *back = [TYImplementCallback createImpLementCallback:perform];
[self addTarget:back action:@selector(callback) forControlEvents:style];
}
為什么會(huì)出現(xiàn)這樣的情況了。這是因?yàn)槲覍?duì)內(nèi)存這個(gè)概論的認(rèn)識(shí)不夠深刻。繼承NSObject的類創(chuàng)建的時(shí)候不用像其它可視化控件一樣有一個(gè)add過(guò)程,這個(gè)add過(guò)程就是將對(duì)象的內(nèi)存加入到堆中。而NSObject沒(méi)有add所以它內(nèi)存一直在棧中,只要一離開(kāi)}這個(gè)對(duì)象的內(nèi)存就沒(méi)有了,而我們操作點(diǎn)擊事件是在出了括號(hào)才執(zhí)行的。所以會(huì)導(dǎo)致我們的程序就會(huì)崩潰。
解決這個(gè)方法還有就是
//這里的作用聲明全局對(duì)象,它內(nèi)存是放在這個(gè)大的對(duì)象堆中。是跟隨大的對(duì)象內(nèi)存消失而消失的。
@interface UIControl()
@end
中寫(xiě)一個(gè)全局聲明的對(duì)象,然后在創(chuàng)建NSObject的類后,就這個(gè)對(duì)象賦值給我們剛才聲明的全局對(duì)象。這樣就能保證我們的NSObject對(duì)象不會(huì)出了括號(hào)就消失了。在分類當(dāng)中沒(méi)有set方法和get方法,也沒(méi)有實(shí)例化屬性發(fā)功能。我們可以通過(guò)runtime機(jī)制進(jìn)行實(shí)現(xiàn)。
代碼:
- (TYImplementCallback *)back{
return objc_getAssociatedObject(self, &backKey);
}
- (void)setBack:(TYImplementCallback *)back {
objc_setAssociatedObject(self, &backKey, back, OBJC_ASSOCIATION_RETAIN);
}
- (void)clickOperation:(void (^) (void))perform style:(UIControlEvents)style {
self.back = [TYImplementCallback createImpLementCallback:perform];
[self addTarget:self.back action:@selector(callback) forControlEvents:style];
}
在我們的開(kāi)發(fā)現(xiàn)在雖然使用了ARC來(lái)進(jìn)行內(nèi)存管理,但是我們還是要對(duì)內(nèi)存管理要有了解。什么樣的情況是在堆中,什么樣的情況是在棧中。我這兩天的錯(cuò)誤就是對(duì)內(nèi)存的不太深入的了解。