ObjecTips

Swift & Objective-C で iOS とか macOS とか

UIKit の Private な UIGestureRecognizer その2

NSLog(@"%@", gestureRecognizer);

の出力結果って見辛いよねって事で、いい感じに調査をするために調査用のログ出力を試みてみる。

通常のログ出力

<UITextTapRecognizer: 0x7ff853734850; state = Possible; delaysTouchesEnded = NO; view = <MyTextField 0x7ff853725f30>; target= <(action=oneFingerTripleTap:, target=<UITextInteractionAssistant 0x7ff853724d50>)>; numberOfTapsRequired = 3>

から
UITextTapRecognizer
action=oneFingerTripleTap:
target=UITextInteractionAssistant
numberOfTapsRequired
numberOfTouchesRequired
あたりだけを表示したい。

ここで問題が。
UIControl の場合

- (NSSet *)allTargets;                                                                  
- (NSArray *)actionsForTarget:(id)target forControlEvent:(UIControlEvents)controlEvent;

というメソッドによって簡単にターゲットとアクションが取得できるけど、UIGestureRecognizer の場合はこれらのメソッドが存在していない。

そこでこの記事で書いた方法で Private なメソッドインスタンス変数を調べてみる。

koze.hatenablog.jp

結果は以下

// Method List of UIGestureRecognizer
reset
description
dealloc
setDelegate:
setDelaysTouchesBegan:
_setRequiresSystemGesturesToFail:
locationInView:
_physicalButtonsBegan:withEvent:
_isDirty
touchesCancelled:withEvent:
ignoreTouch:forEvent:
_updateGestureStateWithEvent:buttonEvent:afterDelay:
_queueForResetIfFinished
_ignorePhysicalButton:forEvent:
_physicalButtonsEnded:withEvent:
_physicalButtonsCancelled:withEvent:
setView:
touchesBegan:withEvent:
touchesMoved:withEvent:
touchesEnded:withEvent:
_setDirty
_requiresSystemGesturesToFail
removeTarget:action:
setDelaysTouchesEnded:
requireGestureRecognizerToFail:
numberOfTouches
_activeTouchesForEvent:
_isRecognized
setCancelsTouchesInView:
canBePreventedByGestureRecognizer:
canPreventGestureRecognizer:
addTarget:action:
_delegateShouldReceiveTouch:
requireOtherGestureToFail:
locationOfTouch:inView:
_connectInterfaceBuilderEventConnection:
_setAcceptsFailureRequiments:
_resetGestureRecognizer
delaysTouchesBegan
_briefDescription
_shouldBeRequiredToFailByGestureRecognizer:
_clearReferencesToRelatedGesture:
_enqueueDelayedTouchesToSend
_clearUpdateTimer
_shouldBegin
_isFriendWithGesture:
_enqueueDelayedTouchToSend:
_delayTouch:forEvent:
_clearDelayedTouches
_willBeginAfterSatisfyingFailureRequirements
_delayTouchesForEvent:
_updateGestureWithEvent:buttonEvent:
_shouldReceiveTouch:
_affectedByGesture:
_delegateCanPreventGestureRecognizer:
_addFailureDependent:
_removeFailureDependent:
_appendDescriptionToString:atLevel:includingDependencies:
cancelsTouchesInView
delaysTouchesEnded
_appendSubclassDescription:
_appendDescription:forDependencies:toString:atLevel:
_failureMap
_setFailureMap:
_delayedTouches
_hasTargets
_shouldRequireFailureOfGestureRecognizer:
shouldRequireFailureOfGestureRecognizer:
shouldBeRequiredToFailByGestureRecognizer:
_centroidOfTouches:excludingEnded:
_distanceBetweenTouches:
_touchWasCancelled:
_requiresGestureRecognizerToFail:
_delayedUpdateGesture
_resetIfFinished
_depthFirstViewCompare:
_addFriendGesture:
_isExcludedByGesture:
_cancelRecognition
_exclude
_addDynamicFailureDependent:
_addDynamicFailureRequirement:
removeFailureRequirement:
_failureRequirementCompleted:withEvent:
_acceptsFailureRequirements
_detach
state
encodeWithCoder:
initWithCoder:
setState:
delegate
_invalidate
init
initWithTarget:action:
view
isEnabled
setEnabled:
// Property List of UIGestureRecognizer
state
delegate
enabled
view
cancelsTouchesInView
delaysTouchesBegan
delaysTouchesEnded
// Ivar List of UIGestureRecognizer
_targets
_delayedTouches
_view
_updateEvent
_updateButtonEvent
_delegate
_friends
_state
_gestureFlags
_failureRequirements
_failureDependents
_dynamicFailureRequirements
_dynamicFailureDependents
_failureMap

Private なインスタンス変数に _targets というドンピシャっぽいものがあった。 これを KVO を使って

NSLog(@"%@", [gestureRecognizer valueForKey:@"targets"]);

このようにしてインスタンス変数を取得してログ出力してみると以下のような結果が得られた。

(
    "(action=oneFingerTripleTap:, target=<UITextInteractionAssistant 0x7f950bf1af90>)"
)

何かしらのクラスの配列になっているっぽい。 そこで今度は以下のようにしてその何かしらのクラスの実態を探る。

この記事のクラス階層を表示する function も加えて以下のようにする。

    id object = [[gestureRecognizer valueForKey:@"targets"] firstObject];
    Class cls = [object class];
    PrintClassHierarchy(cls);
    PrintMethodList(cls);
    PrintPropertyList(cls);
    PrintIvarList(cls);

出力は以下

// Class Hierarchy of UIGestureRecognizerTarget
UIGestureRecognizerTarget : NSObject
// Method List of UIGestureRecognizerTarget
description
// Property List of UIGestureRecognizerTarget
// Ivar List of UIGestureRecognizerTarget
_target
_action

どうやら配列に格納されているのは NSObject のサブクラスの UIGestureRecognizerTarget という Private なクラスで、_target_action という Private なインスタンス変数を持っているらしい。
target と action の方は UIGestureRecognizer のイニシャライザ

- (instancetype)initWithTarget:(id)target action:(SEL)action;

と同じく id型 と SEL型 だろうと推測できる。
descriptionメソッドの返り値も NSString * だと推測できるので、ここまでで分かったことをまとめるとこうなる。

続く