0

I have some problems with my version of this loadingOverlay singleton.

What's supposed to happen, is it comes onto the screen, with a view and a label that has the text, "Loading, please wait." or something like that. then if loading is longer than 2 seconds (i've changed it to 10 for debugging) the text changes to a random cute phrase.

first of all the animation that should change the text doesn't seem to happen. instead, the text just instantly changes.

more importantly, If, for some reason, my asynchronous call block is executed multiple times, I only want the most recent call to it to run, and I want the previous instances of it to terminate before running.

I was reading about callbacks and promises, which look promising. Is that a swifty pattern to follow?

by the way, as I'm learning swift and iOS, I've been experimenting, and I tried [unowned self] and now i'm experimenting with [weak self], but I'm not really certain which is most appropriate here.

// from http://stackoverflow.com/questions/33064908/adding-removing-a-view-overlay-in-swift/33064946#33064946

import UIKit

class LoadingOverlay{
    static let sharedInstance = LoadingOverlay()

    //above swifty singleton syntax from http://krakendev.io/blog/the-right-way-to-write-a-singleton

    var overlayView = UIView()

    var spring: CASpringAnimation!
    var springAway: CASpringAnimation!

    var hidden = false

    private init() {} //This line prevents others from using the default () initializer for this class

    func setupSpringAnimation(startY: CGFloat, finishY: CGFloat) {
        overlayView.layer.position.y = startY
        spring = CASpringAnimation(keyPath: "position.y")
        spring.damping = 10
        spring.fromValue =  startY
        spring.toValue = finishY
        spring.duration = 1.0
        spring.fillMode = kCAFillModeBackwards


    }

    func showOverlay() {
        print("show overlay")
        overlayView.alpha = 1
        hidden = false
        if  let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate,
            let window = appDelegate.window {

            setupSpringAnimation(-window.frame.height / 2, finishY: window.frame.height / 2)
            let overlayViewFramesize = 0.65 * min(window.frame.height, window.frame.width)
            overlayView.frame = CGRectMake(0, 0, overlayViewFramesize, overlayViewFramesize)
            overlayView.center = window.center
            overlayView.backgroundColor = UIColor.greenColor()
            overlayView.clipsToBounds = true
            overlayView.layer.cornerRadius = overlayViewFramesize / 8

            let label = UILabel(frame: CGRectMake(0,0,overlayViewFramesize * 0.8 , overlayViewFramesize))
            label.text = " \nLoading, please wait\n "
            label.tag = 12
            overlayView.addSubview(label)
            label.lineBreakMode = NSLineBreakMode.ByWordWrapping
            label.numberOfLines = 0 //as many as needed


            label.sizeToFit()
            label.textAlignment = NSTextAlignment.Center

            label.center = CGPointMake(overlayViewFramesize / 2, overlayViewFramesize / 2)
            overlayView.bringSubviewToFront(label)
            window.addSubview(overlayView)

            overlayView.layer.addAnimation(spring, forKey: nil)
            RunAfterDelay(10.0) {
                if self.hidden == true { return }

                //strongSelf boilerplate code technique from https://www.raywenderlich.com/133102/swift-style-guide-april-2016-update?utm_source=raywenderlich.com+Weekly&utm_campaign=ea47726fdd-raywenderlich_com_Weekly4_26_2016&utm_medium=email&utm_term=0_83b6edc87f-ea47726fdd-415681129

                UIView.animateWithDuration(2, delay: 0, options: [UIViewAnimationOptions.CurveEaseInOut, UIViewAnimationOptions.BeginFromCurrentState, UIViewAnimationOptions.TransitionCrossDissolve], animations: { [weak self] in
                    guard let strongSelf = self else { return }
                    (strongSelf.overlayView.viewWithTag(12) as! UILabel).text = randomPhrase()
                    (strongSelf.overlayView.viewWithTag(12) as! UILabel).sizeToFit()
                    print ((strongSelf.overlayView.viewWithTag(12) as! UILabel).bounds.width)
                    (strongSelf.overlayView.viewWithTag(12) as! UILabel).center = CGPointMake(overlayViewFramesize / 2, overlayViewFramesize / 2)

                    }, completion: { (finished: Bool)in
                        print ("animation to change label occured")})

            }




        }
    }
    func hideOverlayView() {
        hidden = true
        UIView.animateWithDuration(1.0, delay: 0.0, options: [UIViewAnimationOptions.BeginFromCurrentState], animations: { [unowned self] in
//I know this is clunky... what's the right way?
            (self.overlayView.viewWithTag(12) as! UILabel).text = ""
            self.overlayView.alpha = 0
        }) { [unowned self] _  in
//I know this is clunky. what's the right way?                
            for view in self.overlayView.subviews {
                view.removeFromSuperview()
            }

            self.overlayView.removeFromSuperview()

            print("overlayView after removing:", self.overlayView.description)

        }

        //here i have to deinitialize stuff to prepare for the next use


    }

    deinit {
        print("Loading Overlay deinit")
    }


}
Dave Kliman
  • 441
  • 4
  • 17

1 Answers1

0

What I basically wanted, was to be able to delay a block of code, and possibly cancel it before it executes. I found the answer here:

GCD and Delayed Invoking

Dave Kliman
  • 441
  • 4
  • 17