4

Ok so what I'm trying to do is change the pixel data of a certain image. I want to use a UIView that moves to the right each time it loops as progressbar. However, what is happening is the screen freezes during the calculation and nothing happens until it has finished. The statusbar clock won't update either. Is there a way to move these calculations to the background somehow and still use the screen real estate?

func lock() {

    let lockView =  UIImageView(image: self.photoBackgroundView.image!)
    var progressBar = UIView(frame: CGRectMake(-self.view.width,0,self.view.width,20)
    let increment = progressBar.width/self.photoBackgroundView.width
    var password = self.textField.text!
    if password == "" {
        password = " "
    }
    var currentIndex = 0



    let imageRect = CGRectMake(0, 0, self.photoBackgroundView.image!.size.width,self.photoBackgroundView.image!.size.height)

    UIGraphicsBeginImageContext(self.photoBackgroundView.image!.size)
    let context = UIGraphicsGetCurrentContext()

    CGContextSaveGState(context)
    CGContextDrawImage(context, imageRect, self.photoBackgroundView.image!.CGImage)
    for x in 0...Int(self.photoBackgroundView.image!.size.width) {
        print(x)

        progressBar.frame.origin.x += (CGFloat(x) * increment)
        self.view.addSubView(progressBar)


        for y in 0...Int(self.photoBackgroundView.image!.size.height) {
            let pointColor = lockView.layer.colorOfPoint(CGPoint(x: x, y: y))

            if currentIndex == Array(password.characters).count {
                currentIndex = 0
            }
            let red = encrypt(pointColor.components.red, passwordChar: Array(password.characters)[currentIndex], currentIndex: currentIndex, x: x, y: y)
            currentIndex++
            if currentIndex == Array(password.characters).count {
                currentIndex = 0
            }
            let green = encrypt(pointColor.components.green, passwordChar: Array(password.characters)[currentIndex], currentIndex: currentIndex, x: x, y: y)
            currentIndex++
            if currentIndex == Array(password.characters).count {
                currentIndex = 0
            }
            let blue = encrypt(pointColor.components.blue, passwordChar: Array(password.characters)[currentIndex], currentIndex: currentIndex, x: x, y: y)
            currentIndex++

            CGContextSetRGBFillColor(context, red, green, blue, pointColor.components.alpha)
            CGContextFillRect(context, CGRectMake(CGFloat(x), CGFloat(y), 1, 1))

        }



    }

    CGContextRestoreGState(context)
    let newImage = UIGraphicsGetImageFromCurrentImageContext()
    self.photoBackgroundView.image = newImage
    self.slideView.addSubview(photoBackgroundView)
    self.view.addSubview(self.slideView)
}
SemAllush
  • 477
  • 8
  • 16

2 Answers2

4

You can do these calculations in a background thread.

Swift 2:

let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
    // Put the calculations here
    dispatch_async(dispatch_get_main_queue()) {
        // any updates of the UI need to be here which will be executed in the main thread after your background task completes. For example adding subviews
    }
}

Swift 3:

See this answer

FelixSFD
  • 6,052
  • 10
  • 43
  • 117
  • please add a little bit more information to the answer than just a link. – luk2302 Dec 31 '15 at 13:38
  • I'm now getting memory warnings I didn't get on the main thread, any way of avoiding that? – SemAllush Jan 01 '16 at 20:30
  • @SemAllush FYI, you shouldn't be using any `UIView` based object references from a background thread. You'll need to offload your frame calculations as CGRects and then write those to your `progressBar` when you come back to the main thread in the second dispatch block. However, passing `UIImage` between threads should be fine from my experience. – Awesome-o Jan 10 '16 at 03:04
1

Your screen or UI is freezing as you are doing your heavy calculations in the main thread. Main thread is responsible for updating UI elements, and when you do heavy duty work on mainThread it will block the mainThread and freeze the UI which is NOT recommended.

By default any code you write will run on main thread. You need to write your code in background threads separately so that both the mainThread and BGthread can run simultaneously.

You can use NSOperationQueue or GCD (Grand Central Dispatch) to easily write functions to run in some other background threads.

Please follow this link for further explanations.

Saheb Roy
  • 5,899
  • 3
  • 23
  • 35