一個擴大按鈕點擊範圍的小技巧,在不改變frame的前提下,可通過以下方法實現:
關聯是指把兩個對象相互關聯起來,使得其中的一個對象作爲另外一個對象的一部分。
在類的定義之外爲類增加額外的存儲空間
使用關聯,我們可以不用修改類的定義而爲其對象增加存儲空間。這在我們無法訪問到類的源碼的時候或者是考慮到二進制兼容性的時候是非常有用。關聯是基於關鍵字的,因此,我們可以爲任何對象增加任意多的關聯,每個都使用不同的關鍵字即可。關聯是可以保證被關聯的對象在關聯對象的整個生命週期都是可用的(在垃圾自動回收環境下也不會導致資源不可回收)。
創建關聯
創建關聯要使用到Objective-C的運行時函數:objc_setAssociatedObject來把一個對象與另外一個對象進行關聯。該函數需要四個參數:源對象,關鍵字,關聯的對象和一個關聯策略。
■ 關鍵字是一個void類型的指針。每一個關聯的關鍵字必須是唯一的。通常都是會採用靜態變量來作爲關鍵字。
■ 關聯策略表明了相關的對象是通過賦值,保留引用還是複製的方式進行關聯的;還有這種關聯是原子的還是非原子的。這裏的關聯策略和聲明屬性時的很類似。這種關聯策略是通過使用預先定義好的常量來表示的。
獲取相關聯的對象
獲取相關聯的對象時使用Objective-C函數objc_getAssociatedObject。
斷開關聯
斷開關聯是使用objc_setAssociatedObject函數,傳入nil值即可。使用函數objc_removeAssociatedObjects可以斷開所有關聯。通常情況下不建議使用這個函數,因爲他會斷開所有關聯。只有在需要把對象恢復到“原始狀態”的時候纔會使用這個函數。
下面是例子:
@implementation UIButton(extend)
static char topNameKey;
static char rightNameKey;
static char bottomNameKey;
static char leftNameKey;
-(void)setEnlargeEdgeWithTop:(CGFloat)top right:(CGFloat)right bottom:(CGFloat)bottom left:(CGFloat)left{
objc_setAssociatedObject(self, &topNameKey, [NSNumber numberWithFloat:top], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &rightNameKey, [NSNumber numberWithFloat:right], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &bottomNameKey, [NSNumber numberWithFloat:bottom], OBJC_ASSOCIATION_COPY_NONATOMIC);
objc_setAssociatedObject(self, &leftNameKey, [NSNumber numberWithFloat:left], OBJC_ASSOCIATION_COPY_NONATOMIC);
}
-(CGRect)enlargedRect{
NSNumber *topEdge = objc_getAssociatedObject(self, &topNameKey);
NSNumber *rightEdge = objc_getAssociatedObject(self, &rightNameKey);
NSNumber *bottomEdge = objc_getAssociatedObject(self, &bottomNameKey);
NSNumber *leftEdge = objc_getAssociatedObject(self, &leftNameKey);
CGRect rect = CGRectZero;
if(topEdge && rightEdge && bottomEdge && leftEdge){
rect = CGRectMake(self.bounds.origin.x-leftEdge.floatValue, self.bounds.origin.y-topEdge.floatValue, self.bounds.size.width+leftEdge.floatValue+rightEdge.floatValue, self.bounds.size.height+topEdge.floatValue+bottomEdge.floatValue);
}else{
rect = self.bounds;
}
return rect;
}
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
CGRect rect = [self enlargedRect];
if(CGRectEqualToRect(rect, self.bounds)){
return [super hitTest:point withEvent:event];
}
return CGRectContainsPoint(rect, point) ? self : nil;
}