Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot override ImageDisplayingView method in UIImageView subclass #38

Closed
ValCanBuild opened this issue Oct 31, 2015 · 6 comments
Closed
Labels

Comments

@ValCanBuild
Copy link

I'm trying to wrap the Nuke functionality in my own UIImageView subclass. Due to ImageLoadingViewExtensions.swift, I am unable to override the the func nk_imageTask(task: ImageTask, didFinishWithResponse response: ImageResponse, options: ImageViewLoadingOptions?) where I want to place some custom logic.

Is there any way this can be changed to allow me to do that?

@kean
Copy link
Owner

kean commented Oct 31, 2015

Ok, I've just tested it and I can confirm that Swift calls the default implementation provided in public extension ImageDisplayingView where Self: View, which shouldn't be the case.

@kean
Copy link
Owner

kean commented Oct 31, 2015

As a workaround you can set a custom handler on ImageViewLoadingController:

class CustomImageView: UIImageView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.nk_imageLoadingController.handler = { task, response, options in
            // your nk_imageTask(task: ImageTask, didFinishWithResponse response: ImageResponse, options: ImageViewLoadingOptions?) implementation
        }
    }
}

@ValCanBuild
Copy link
Author

Thank, Kean, that works great. Want me to close the issue or will you leave it open to investigate?

@kean kean added the question label Oct 31, 2015
@kean
Copy link
Owner

kean commented Oct 31, 2015

Please leave it open. Users should be able to override methods declared in ImageDisplayingView protocol, at least that was the intended behaviour. I should figure out why virtual dispatch doesn't work here.

@kean
Copy link
Owner

kean commented Nov 12, 2015

After some research I've found several different issues related to methods dispatch with protocol extensions that still hasn't been fixed in Xcode 7.

Here's the related one http://www.openradar.me/23067007. You have class A that conforms to protocol P that has default implementation of method foo. If you create subclass B of class A and implement method foo it never gets called unless class A also provides an implementation of foo method.

And that's how it works in Nuke:

  1. If you implement nk_imageTask(_:didFinishWithResponse:options:) method in a class that declares conformance to ImageDisplayingView protocol (for instance UIImageView) then this method gets called (as expected):
    extension UIImageView: ImageDisplayingView, ImageLoadingView {
        public var nk_image: UIImage? {
            get { return self.image }
            set { self.image = newValue }
        }

        public func nk_imageTask(task: ImageTask, didFinishWithResponse response: ImageResponse, options: ImageViewLoadingOptions?) {
            print("UIImageView method called")
        }
    }
  1. However if you implement nk_imageTask(_:didFinishWithResponse:options:) method in a subclass of UIImageView and don't implement this method in UIImageView then this method never gets called (this is a bug which is the same as in the radar).
public class NKImageView: UIImageView {

}

extension NKImageView {
    public override var nk_image: UIImage? {
        get { return self.image }
        set { self.image = newValue }
    }

    public func nk_imageTask(task: ImageTask, didFinishWithResponse response: ImageResponse, options: ImageViewLoadingOptions?) {
        print("NKImageView method never gets called")
    }
}
  1. If you implement nk_imageTask(_:didFinishWithResponse:options:) method in both UIImageView and NKImageView classes then you get the following error in NKImageView class (as of Xcode 7.1):

screen shot 2015-11-13 at 02 29 55

The error message is pretty obvious. And as you can see properties already can be overridden and get called as expected.

@kean
Copy link
Owner

kean commented Nov 12, 2015

This behaviour (http://www.openradar.me/23067007) doesn't match the documentation that clearly states that:

You can use protocol extensions to provide a default implementation to any method or property requirement of that protocol. If a conforming type provides its own implementation of a required method or property, that implementation will be used instead of the one provided by the extension.

Same thing holds with extensions with where clauses (which I've also tested):

If a conforming type satisfies the requirements for multiple constrained extensions that provide implementations for the same method or property, Swift will use the implementation corresponding to the most specialized constraints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants