Search code examples
swiftuiviewuitapgesturerecognizer

How to make an extension of UIView for a convenient tapGestureRecognizer?


This is the extension of UIView to add easily a UITapGestureRecognizer to UIImageView:

extension UIView {

    fileprivate struct AssociatedObjectKeys {
        static var tapGestureRecognizer = "MediaViewerAssociatedObjectKey_mediaViewer"
    }

    fileprivate typealias Action = (() -> Void)?

    fileprivate var tapGestureRecognizerAction: Action? {
        set {
            if let newValue = newValue {
                // Computed properties get stored as associated objects
                objc_setAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) //Forming 'UnsafeRawPointer' to an inout variable of type String exposes the internal representation rather than the string contents.
            }
        }
        get {
            let tapGestureRecognizerActionInstance = objc_getAssociatedObject(self, &AssociatedObjectKeys.tapGestureRecognizer) as? Action //Forming 'UnsafeRawPointer' to an inout variable of type String exposes the internal representation rather than the string contents.
            return tapGestureRecognizerActionInstance
        }
    }

    public func addTapGestureRecognizer(action: (() -> Void)?) {
        self.isUserInteractionEnabled = true
        self.tapGestureRecognizerAction = action
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
        self.addGestureRecognizer(tapGestureRecognizer)
    }

    @objc fileprivate func handleTapGesture(sender: UITapGestureRecognizer) {
        if let action = self.tapGestureRecognizerAction {
            action?()
        } else {
            print("no action")
        }
    }
}

But xcode tells me this twice for the set and the get methods: >Forming 'UnsafeRawPointer' to an inout variable of type String exposes the internal representation rather than the string contents.

What do i have to do to silent it? I notice that the code works but with this 2 warnings. Thank u


Solution

  • The warning is warning you that &AssociatedObjectKeys.tapGestureRecognizer does not evaluate to a pointer that points to a buffer containing the string's characters (as some people would expect that). Instead, it points to the string's "internal representation".

    See also this post for a slightly differently-worded warning that gets emitted when you try to use & to get a raw pointer of other non-trivial types. The warning you got is kind of the specialised version of that, specifically for strings.

    Of course, you don't want to get the contents of the string in this case. You just want a fixed address as the key of an associated object, so the warning is a false positive. The simplest way to silence the warning is to use a trivial type (see here for what "trivial" means) like Int:

    @MainActor
    static var tapGestureRecognizer = 0
    

    The key for an associated object doesn't need to be a pointer to a string. I also isolated it to MainActor to silence concurrency-related warnings. These warnings are similarly false positives. All you want here is a fixed address - you don't care about the value stored in tapGestureRecognizer.