YYKit源码探究(三十一) —— UIControl分类(一)

版本记录

版本号 时间
V1.0 2018.03.29

前言

iOS圈内有几个人大家基本都知道,比如说王巍、唐巧,还有YYKit框架的作者现任职于滴滴的郭曜源 - ibireme等。这里有一篇唐巧对他的专访,还有他的 GitHub - Yaoyuan博客,这里贴出来框架YYKit 框架。接下来几篇我们就一起来看一下这个框架。感兴趣的可以看上面写的几篇。
1. YYKit源码探究(一) —— 基本概览
2. YYKit源码探究(二) —— NSString分类之Hash(一)
3. YYKit源码探究(三) —— NSString分类之Encode and decode(二)
4. YYKit源码探究(四) —— NSString分类之Drawing(三)
5. YYKit源码探究(五) —— NSString分类之Regular Expression(四)
6. YYKit源码探究(六) —— NSString分类之NSNumber Compatible(五)
7. YYKit源码探究(七) —— NSString分类之Utilities(六)
8. YYKit源码探究(八) —— NSNumber分类(一)
9. YYKit源码探究(九) —— UIFont分类之架构分析和Font Traits(一)
10. YYKit源码探究(十) —— UIFont分类之Create font(二)
11. YYKit源码探究(十一) —— UIFont分类之Load and unload font(三)
12. YYKit源码探究(十二) —— UIFont分类之Dump font data(四)
13. YYKit源码探究(十三) —— UIImage分类之框架结构和Create image部分(一)
14. YYKit源码探究(十四) —— UIImage分类之Image Info(二)
15. YYKit源码探究(十五) —— UIImage分类之Modify Image(三)
16. YYKit源码探究(十六) —— UIImage分类之Image Effect(四)
17. YYKit源码探究(十七) —— UIImageView分类之架构和image部分(一)
18. YYKit源码探究(十八) —— UIImageView分类之highlight image部分(二)
19. YYKit源码探究(十九) —— UIScreen分类(一)
20. YYKit源码探究(二十) —— UIScrollView分类(一)
21. YYKit源码探究(二十一) —— UITableView分类(一)
22. YYKit源码探究(二十二) —— UITextField分类(一)
23. YYKit源码探究(二十三) —— UIView分类(一)
24. YYKit源码探究(二十四) —— UIPasteboard分类(一)
25. YYKit源码探究(二十五) —— UIGestureRecognizer分类(一)
26. YYKit源码探究(二十六) —— UIDevice分类框架及Device Information(一)
27. YYKit源码探究(二十七) —— UIDevice分类之Network Information(二)
28. YYKit源码探究(二十八) —— UIDevice分类之Disk Space(三)
29. YYKit源码探究(二十九) —— UIDevice分类之Memory Information(四)
30. YYKit源码探究(三十) —— UIDevice分类之CPU Information(五)

回顾

上一篇主要介绍了UIDevice CPU Information分类,这一篇主要看一下UIControl分类部分。


API 文档

下面我们就看一下API接口。

/**
 Removes all targets and actions for a particular event (or events)
 from an internal dispatch table.
 */
- (void)removeAllTargets;

/**
 Adds or replaces a target and action for a particular event (or events)
 to an internal dispatch table.
 
 @param target         The target object—that is, the object to which the
                       action message is sent. If this is nil, the responder
                       chain is searched for an object willing to respond to the
                       action message.
 
 @param action         A selector identifying an action message. It cannot be NULL.
 
 @param controlEvents  A bitmask specifying the control events for which the
                       action message is sent.
 */
- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

/**
 Adds a block for a particular event (or events) to an internal dispatch table.
 It will cause a strong reference to @a block.
 
 @param block          The block which is invoked then the action message is
                       sent  (cannot be nil). The block is retained.
 
 @param controlEvents  A bitmask specifying the control events for which the
                       action message is sent.
 */
- (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;

/**
 Adds or replaces a block for a particular event (or events) to an internal
 dispatch table. It will cause a strong reference to @a block.
 
 @param block          The block which is invoked then the action message is
                       sent (cannot be nil). The block is retained.
 
 @param controlEvents  A bitmask specifying the control events for which the
                       action message is sent.
 */
- (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;

/**
 Removes all blocks for a particular event (or events) from an internal
 dispatch table.
 
 @param controlEvents  A bitmask specifying the control events for which the
                       action message is sent.
 */
- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;

下面我们就详细的看一下这个API

1. - (void)removeAllTargets;

该方法的作用就是从一个内部的dispatch table中移除某一特定event的所有的targetsactions

方法实现

下面我们看一下方法的实现。

- (void)removeAllTargets {
    [[self allTargets] enumerateObjectsUsingBlock: ^(id object, BOOL *stop) {
        [self removeTarget:object action:NULL forControlEvents:UIControlEventAllEvents];
    }];
    [[self _yy_allUIControlBlockTargets] removeAllObjects];
}

- (NSMutableArray *)_yy_allUIControlBlockTargets {
    NSMutableArray *targets = objc_getAssociatedObject(self, &block_key);
    if (!targets) {
        targets = [NSMutableArray array];
        objc_setAssociatedObject(self, &block_key, targets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return targets;
}

2. - (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

为某一特定的event添加或者移除targetaction到一个内部dispatch table

  • target:目标对象 - 即消息发送到的对象。 如果这是nil,响应者链会搜索一个愿意回应该动作消息的对象。
  • action:一个标识动作消息的选择器。 它不能为NULL。
  • controlEvents:指定发送操作消息的控件事件的位掩码。

方法实现

下面我们看一下方法的实现。

- (void)setTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
    if (!target || !action || !controlEvents) return;
    NSSet *targets = [self allTargets];
    for (id currentTarget in targets) {
        NSArray *actions = [self actionsForTarget:currentTarget forControlEvent:controlEvents];
        for (NSString *currentAction in actions) {
            [self removeTarget:currentTarget action:NSSelectorFromString(currentAction)
                forControlEvents:controlEvents];
        }
    }
    [self addTarget:target action:action forControlEvents:controlEvents];
}

3. - (void)addBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;

将特定事件(或事件)的块添加到内部dispatch table中。 它会引起对@a block的强烈引用。

  • block:当action消息被发送时调用block(不能为nil),该块被引用。
  • controlEvents:指定发送操作消息的控件事件的位掩码。

方法实现

下面我们看一下方法的实现。

- (void)addBlockForControlEvents:(UIControlEvents)controlEvents
                           block:(void (^)(id sender))block {
    if (!controlEvents) return;
    _YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc]
                                       initWithBlock:block events:controlEvents];
    [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
    NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
    [targets addObject:target];
}
@interface _YYUIControlBlockTarget : NSObject

@property (nonatomic, copy) void (^block)(id sender);
@property (nonatomic, assign) UIControlEvents events;

- (id)initWithBlock:(void (^)(id sender))block events:(UIControlEvents)events;
- (void)invoke:(id)sender;

@end

4. - (void)setBlockForControlEvents:(UIControlEvents)controlEvents block:(void (^)(id sender))block;

将特定事件(或事件)的块添加或替换到内部dispatch table中。 它会引起对@a block的强烈引用。

  • block:当action消息被发送时调用block(不能为nil),该块被引用。
  • controlEvents:指定发送操作消息的控件事件的位掩码。

方法实现

- (void)setBlockForControlEvents:(UIControlEvents)controlEvents
                           block:(void (^)(id sender))block {
    [self removeAllBlocksForControlEvents:UIControlEventAllEvents];
    [self addBlockForControlEvents:controlEvents block:block];
}

- (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents {
    if (!controlEvents) return;
    
    NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
    NSMutableArray *removes = [NSMutableArray array];
    for (_YYUIControlBlockTarget *target in targets) {
        if (target.events & controlEvents) {
            UIControlEvents newEvent = target.events & (~controlEvents);
            if (newEvent) {
                [self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
                target.events = newEvent;
                [self addTarget:target action:@selector(invoke:) forControlEvents:target.events];
            } else {
                [self removeTarget:target action:@selector(invoke:) forControlEvents:target.events];
                [removes addObject:target];
            }
        }
    }
    [targets removeObjectsInArray:removes];
}

- (void)addBlockForControlEvents:(UIControlEvents)controlEvents
                           block:(void (^)(id sender))block {
    if (!controlEvents) return;
    _YYUIControlBlockTarget *target = [[_YYUIControlBlockTarget alloc]
                                       initWithBlock:block events:controlEvents];
    [self addTarget:target action:@selector(invoke:) forControlEvents:controlEvents];
    NSMutableArray *targets = [self _yy_allUIControlBlockTargets];
    [targets addObject:target];
}

5. - (void)removeAllBlocksForControlEvents:(UIControlEvents)controlEvents;

将内部dispatch table中特定事件(或事件)的所有block移除。

  • controlEvents:指定发送操作消息的控件事件的位掩码。

方法实现

这个方法在上面粘出来了,这里就不多说了。

后记

本篇主要介绍了UIControl的一个分类,感兴趣的给个赞或者关注,谢谢~~~~

推荐阅读更多精彩内容