3

Situation: I am creating an imageGallery which is a viewController that I am presenting modally. I have created it all programatically, I haven't touched the storyboard. The viewController has a scrollView that contains ImageViews, which each hold an image. I have set scrollView.isPagingEnabled = true and it works as expected, I can scroll through the images fine.

Issue: I am trying to do some work when the scrollView has scrolled. I have set the delegate (which seems to be the main issue people have had when I searched for an answer) but scrollViewDidScroll never gets called. I'm completely at a loss for what is happening.I've tried quite a lot of different things, but have now run out of ideas

@objc public class ImageGallery: UIViewController, UIScrollViewDelegate {

// MARK:- VARIABLES

/// An array of imageItems
@objc public var galleryItems = [ImageGalleryItem]()

/// The index of the image the gallery should start at
@objc public var startingIndex: NSNumber?

/// The UIImage to display if there is an error
@objc public var errorImage: UIImage?

/// The UIImage to display if the ImageGalleryItem doesn't have an image
@objc public var defaultImage: UIImage?

var scrollView: UIScrollView!

// MARK:- INITS

/// Initialiser for ImageGallery passing an array of ImageGalleryItems
///
/// - Parameter ImageGalleryItems: an array of ImageGalleryItems
@objc public init() {

    self.defaultImage = UIImage(named: "default", in: getResourceBundle(), compatibleWith: nil)!
    self.errorImage = UIImage(named: "error", in: getResourceBundle(), compatibleWith: nil)!
    super.init(nibName:nil, bundle:nil)
}


@objc public required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder);
}


// MARK:- VIEW LIFECYCLES
override public func viewDidLoad() {

    super.viewDidLoad()

    configureScrollView()

    self.scrollView.delegate = self
    configureImageViews()
    configurePresentationDefaults()
}


func configureScrollView() {

    self.scrollView = UIScrollView(frame: view.frame)

    self.scrollView.isPagingEnabled = true
    self.scrollView.contentOffset = CGPoint(x: CGFloat(truncating: startingIndex ?? 0) * UIScreen.main.bounds.width, y: 0)

    let imagesCount = galleryItems.count
        let contentWidth = CGFloat(imagesCount) * UIScreen.main.bounds.width
        self.scrollView.contentSize = CGSize(width: contentWidth, height: UIScreen.main.bounds.height)


    if let toolbar = configureToolBar() {

        view.addSubview(self.scrollView)
        view.addSubview(toolbar)
        view.bringSubviewToFront(toolbar)
    }
}

private func scrollViewDidScroll(_ scrollView: UIScrollView) {
    print("delegate")
}

Update

I was missing an !

private func scrollViewDidScroll(_ scrollView: UIScrollView!) {
    print("delegate")
}

Did the trick.

Gareth Miller
  • 332
  • 1
  • 3
  • 10

3 Answers3

4

Remove private keyword

func scrollViewDidScroll(_ scrollView: UIScrollView)
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • Yeah, I already tried that, I only added `private` because xcode was showing a warning. – Gareth Miller Nov 11 '18 at 12:02
  • FYI, Xcode 10.2.1 (which has Swift 5) has a bug where this function will not be called if you have `Swift Compilation Mode` set to `Incremental builds`. The answer is to add `@objc` before the function. See https://stackoverflow.com/questions/55592341/xcode-10-2-with-swift-5-0-compiler-protocol-inheritance-issue – William Grand Jun 03 '19 at 19:39
1

You issue comes from the private access level keyword with the scrollViewDidScroll: delegate method. The UIScrollViewDelegate is an NSObject and as the method is private it can't see the method and so the delegate method is not called. As you class is public, you need to declare the method with a public access level.

Just try this:

public func scrollViewDidScroll(_ scrollView: UIScrollView) {
    print("delegate")
}
Yannick Loriot
  • 7,107
  • 2
  • 33
  • 56
  • Yeah, I already tried that, I only added `private` because xcode was showing a warning. It didn't change anything – Gareth Miller Nov 11 '18 at 12:03
  • I didn't notice that your class was `public`, so you need to declare the delegate method as public too. I've edited the post. – Yannick Loriot Nov 11 '18 at 12:05
  • `private func scrollViewDidScroll(_ scrollView: UIScrollView!)` fixed the issue – Gareth Miller Nov 11 '18 at 12:08
  • Which swift version are you using? Because the API signature is without the `!`. See https://developer.apple.com/documentation/uikit/uiscrollviewdelegate/1619392-scrollviewdidscroll – Yannick Loriot Nov 11 '18 at 12:12
0

I was missing an !

private func scrollViewDidScroll(_ scrollView: UIScrollView!) {
    print("delegate")
}

Solved the issue.

Gareth Miller
  • 332
  • 1
  • 3
  • 10
  • Hi, Aplogy that I'm messaging you with unrelated article - but I couldn't find anyway to contact to you. I'm having same error with Charles like you. Have you solved the issue? https://webcache.googleusercontent.com/search?q=cache:RtY4iOelMDEJ:https://stackoverflow.com/questions/66581205/every-request-is-failing-in-charles-proxy-with-a-503-timeout-or-503-cannot-alloc+&cd=1&hl=en&ct=clnk&gl=ie – AutumnSky Mar 31 '21 at 12:50