addTarget : action : forControlEvents : method에 해당하는 UIButton 블록
주변을 둘러싼지만 인터넷이나 애플 문서 어디에서 사용할 수 없습니다.
그러나 iOS4는 다음과 같은 API를 차단하고 있습니까?
[button addTarget:self action:@selector(tappy:) forControlEvents:UIControlEventTouchUpInside];
나는 카테고리를 사용하여 구현 될 수 있다고 생각하지만 극도의 게으름으로 인해 직접 작성하지 않을 것입니다. :)
이와 같은 것이 굉장 할 것입니다.
[button handleControlEvent:UIControlEventTouchUpInside withBlock:^ { NSLog(@"I was tapped!"); }];
방금 구현했습니다. 그것은 매력처럼 작동합니다!
그리고 어렵지도.
typedef void (^ActionBlock)();
@interface UIBlockButton : UIButton {
ActionBlock _actionBlock;
}
-(void) handleControlEvent:(UIControlEvents)event
withBlock:(ActionBlock) action;
@end
@implementation UIBlockButton
-(void) handleControlEvent:(UIControlEvents)event
withBlock:(ActionBlock) action
{
_actionBlock = action;
[self addTarget:self action:@selector(callActionBlock:) forControlEvents:event];
}
-(void) callActionBlock:(id)sender{
_actionBlock();
}
@end
공용 Foundation / UI 클래스에 추가 된 블록 라이브러리 인 BlocksKit이 있습니다. 다음은 문서 입니다.
UIButton의 하위 클래스는 UIControl 범주를 추가합니다 .
[button addEventHandler:^(id sender) {
//do something
} forControlEvents:UIControlEventTouchUpInside];
컬렉션 (맵, 필터 등), 뷰 관련 항목 대한 블록 / 기능 추가 있습니다.
참고 : Swift에서는 잘 작동하지 않습니다.
다음은 작업 범주 구현입니다. 현재 형식에서는 DEBUG
. 사용자 상호 작용과 타이밍이 중요 할 때 다양한 코드 비트를 테스트하기 위해 범주를 함수 (아래 포함)와 함께 사용합니다. 다시 말하지만 이것은 개발 / 디버그 목적으로 만 사용 #ifdef DEBUG
됩니다.
#ifdef DEBUG
#import <objc/runtime.h>
static char UIButtonBlockKey;
@interface UIButton (UIBlockButton)
- (void)handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock)block;
- (void)callActionBlock:(id)sender;
@end
@implementation UIButton (UIBlockButton)
- (void)handleControlEvent:(UIControlEvents)event withBlock:(ActionBlock)block {
objc_setAssociatedObject(self, &UIButtonBlockKey, block, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self action:@selector(callActionBlock:) forControlEvents:event];
}
- (void)callActionBlock:(id)sender {
ActionBlock block = (ActionBlock)objc_getAssociatedObject(self, &UIButtonBlockKey);
if (block) {
block();
}
}
@end
void DSAddGlobalButton(NSString *title, ActionBlock block) {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitle:title forState:UIControlStateNormal];
[button handleControlEvent:UIControlEventTouchUpInside withBlock:block];
[button sizeToFit];
[button setFrame:(CGRect){{100.0f, 100.0f}, [button frame].size}];
UIView *firstView = [[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0];
[firstView addSubview:button];
}
#endif
이 작업을 위해 라이브러리를 만들었습니다!
그것은 지원 UIControl
( UIButton
) UIBarButtonItem
,,와 UIGestureRecognizer
. CocoaPods를 사용하여 지원합니다.
https://github.com/lavoy/ALActionBlocks
// Assuming you have a UIButton named 'button'
[button handleControlEvents:UIControlEventTouchUpInside withBlock:^(id weakControl) {
NSLog(@"button pressed");
}];
설치
pod 'ALActionBlocks'
스위프트 4
여기에 해결책이 있습니다.
class ClosureSleeve {
let closure: () -> ()
init(attachTo: AnyObject, closure: @escaping () -> ()) {
self.closure = closure
objc_setAssociatedObject(attachTo, "[\(arc4random())]", self, .OBJC_ASSOCIATION_RETAIN)
}
@objc func invoke() {
closure()
}
}
extension UIControl {
func addAction(for controlEvents: UIControlEvents = .primaryActionTriggered, action: @escaping () -> ()) {
let sleeve = ClosureSleeve(attachTo: self, closure: action)
addTarget(sleeve, action: #selector(ClosureSleeve.invoke), for: controlEvents)
}
}
사용 예 :
button.addAction {
print("button pressed")
}
이 글을 오래전에 작성했는데 이미 문제를 해결하는 방법이 아닙니다 !!! UIButton을 서브 클래 싱하면 가치가없는 지뢰밭이 생성됩니다. Shayne Sweeney의 카테고리를 사용합니다 (그의 예제 제작을 준비하기 위해 여러 가지 수정으로 답변을 업데이트했습니다 ... 빨리 승인을 받기 바랍니다).
----- 오리지널 포스트 -----
Martin이 게시 한 코드는 UIControlEventTouchUpInside를 할당하는 경우에만 작동하지만 몇 가지 문제가 있습니다.
- handleControlEvent :를 두 번 이상 호출하면 게시 된 코드로 블록이됩니다.
- 둘 이상의 이벤트 유형을 할당하면 이벤트에 대해 마지막 블록이 실행됩니다.
내 코드에서는 iOS4 + (3.2가 아님)에서만 작동하는 object-c 객체로 취급되는 블록에 의존하고 있습니다. 버튼 상태 (예 : 애니메이션)에 대해 특별한 작업을하고 싶을 때 잘 작동합니다. 일반적인 클릭을 처리하기 위해 clickedButton 블록을 사용할 수 있습니다.
#import <UIKit/UIKit.h>
@interface ButtWithBlockActions : UIButton {
void (^downBlock_)(void);
void (^upBlock_)(void);
void (^clickedBlock_)(void);
}
@property(nonatomic,retain) void (^downBlock)(void);
@property(nonatomic,retain) void (^upBlock)(void);
@property(nonatomic,retain) void (^clickedBlock)(void);
@end
#import "ButtWithBlockActions.h"
@implementation ButtWithBlockActions
- (void)dealloc {
[downBlock_ release];
[upBlock_ release];
[clickedBlock_ release];
[super dealloc];
}
- (void (^)(void))downBlock { return downBlock_; }
- (void) fireDownBlock { downBlock_(); }
- (void) setDownBlock:(void (^)(void))block {
if(downBlock_) {
[self removeTarget:self action:@selector(fireDownBlock) forControlEvents:UIControlEventTouchDown];
[self removeTarget:self action:@selector(fireDownBlock) forControlEvents:UIControlEventTouchDragEnter];
[downBlock_ release];
}
downBlock_ = [block copy];
if(downBlock_) {
[self addTarget:self action:@selector(fireDownBlock) forControlEvents:UIControlEventTouchDown];
[self addTarget:self action:@selector(fireDownBlock) forControlEvents:UIControlEventTouchDragEnter];
}
}
- (void (^)(void))upBlock { return upBlock_; }
- (void) fireUpBlock { upBlock_(); }
- (void) setUpBlock:(void (^)(void))block {
if(upBlock_) {
[self removeTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchUpInside];
[self removeTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchUpOutside];
[self removeTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchDragOutside];
[self removeTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchCancel];
[upBlock_ release];
}
upBlock_ = [block copy];
if(upBlock_) {
[self addTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchUpInside];
[self addTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchUpOutside];
[self addTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchDragOutside];
[self addTarget:self action:@selector(fireUpBlock) forControlEvents:UIControlEventTouchCancel];
}
}
- (void (^)(void))clickedBlock { return clickedBlock_; }
- (void) fireClickedBlock { clickedBlock_(); }
- (void) setClickedBlock:(void (^)(void))block {
if(clickedBlock_) {
[self removeTarget:self action:@selector(fireClickedBlock) forControlEvents:UIControlEventTouchUpInside];
[clickedBlock_ release];
}
clickedBlock_ = [block copy];
if(clickedBlock_) {
[self addTarget:self action:@selector(fireClickedBlock) forControlEvents:UIControlEventTouchUpInside];
}
}
@end
블록의 잠재 능력을 이끌어내는 REKit 이 있습니다 . 블록을 사용하여 인스턴스에 메소드를 추가 / 재정의 기능을 제공합니다.
REKit을 사용하면 즉시 buttonAction에 응답하는 오리를 동적으로 만들 수 있습니다.
id target;
target = [[NSObject alloc] init];
[target respondsToSelector:@selector(buttonAction) withKey:nil usingBlock:^(id receiver) {
// Do something…
}];
[button addTarget:target action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
하위 클래스 나 카테고리를 만들 필요가 없습니다.
시작 / 액션 패러다임 도입 패턴에 REKit을 사용할 수 있습니다.
작은 도우미 클래스를 사용하는 것이 아니라 다양합니다.
@interface Handler : NSObject
@end
@implementation Handler {
void (^block)(id);
}
+ (Handler *)create:(void (^)(id))block {
Handler *result = [[Handler alloc] init];
result->block = block;
return result;
}
- (void)call:(id)sender {
block(sender);
}
@end
다음과 같이 사용하십시오.
Handler *handler = [Handler create:^(id sender) {
// ... handle the event, using local state captured by the block ...
}];
// store the handler because the target is not retained in addTarget
[handlers addObject:handler];
[button addTarget:handler action:@selector(call:) forControlEvents:UIControlEventTouchUpInside];
내가 채찍질 한 확장 / 카테고리 기반 구현. OBJC 관련 개체를 사용하는 것은 안티 패턴이 아닙니다. : 피
import UIKit
// MARK: UIControl Block based actions
typealias ActionBlock = (UIControl) -> ()
class UIButtonActionDelegate : NSObject {
let actionBlock : ActionBlock
init(actionBlock: ActionBlock) {
self.actionBlock = actionBlock
}
func triggerBlock(control : UIControl) {
actionBlock(control)
}
}
private var actionHandlersKey: UInt8 = 0
extension UIControl {
var actionHandlers: NSMutableArray { // cat is *effectively* a stored property
get {
return associatedObject(self, key: &actionHandlersKey, initialiser: { () -> NSMutableArray in
return NSMutableArray()
})
}
set { associateObject(self, key: &actionHandlersKey, value: newValue) }
}
func addBlockForEvents(events: UIControlEvents, block: ActionBlock) {
let actionDelegate = UIButtonActionDelegate(actionBlock: block)
actionHandlers.addObject(actionDelegate) // So it gets retained
addTarget(actionDelegate, action: #selector(UIButtonActionDelegate.triggerBlock(_:)), forControlEvents: events)
}
}
// MARK: Associated Object wrapper
func associatedObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
initialiser: () -> ValueType)
-> ValueType {
if let associated = objc_getAssociatedObject(base, key)
as? ValueType { return associated }
let associated = initialiser()
objc_setAssociatedObject(base, key, associated,
.OBJC_ASSOCIATION_RETAIN)
return associated
}
func associateObject<ValueType: AnyObject>(
base: AnyObject,
key: UnsafePointer<UInt8>,
value: ValueType) {
objc_setAssociatedObject(base, key, value,
.OBJC_ASSOCIATION_RETAIN)
}
'ProgramingTip' 카테고리의 다른 글
Convert.ChangeType 및 열거 형으로 변환? (0) | 2020.11.28 |
---|---|
로깅, StreamHandler 및 표준 스트림 (0) | 2020.11.27 |
ORA-00904 : 잘못된 식별자 (0) | 2020.11.27 |
명령의 배열에 할당 할당입니까? (0) | 2020.11.27 |
C의 수학 상수 PI 값 (0) | 2020.11.27 |