random
random

Reputation: 8608

Iterating through NSArray works...sometimes

I'm iterating through an array of UIImages that all need to be rotated by 90 degrees. This works...sometimes.

I'll randomly get a case where 2 or 3 of the images failed to rotate but I can't consistently reproduce so debugging has been troublesome.

Here is how I'm looping through my array:

func processPhotosForRotation(completion:() -> Void) {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {

        for (index,image) in self.frameImages.enumerate() {

            let flippedImage = image.imageRotatedByDegrees(90, flip: false)
            self.frameImages[index] = flippedImage
        }

        //I need the images forwards, then backwards
        self.frameImages.appendContentsOf(self.frameImages.reverse())

        dispatch_async(dispatch_get_main_queue()) {
            completion()
        }
    }
}

Here is how I'm rotating the images:

extension UIImage {

    public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage {

        let degreesToRadians: (CGFloat) -> CGFloat = {
            return $0 / 180.0 * CGFloat(M_PI)
        }

        // calculate the size of the rotated view's containing box for our drawing space
        let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size))
        let t = CGAffineTransformMakeRotation(degreesToRadians(degrees));
        rotatedViewBox.transform = t
        let rotatedSize = rotatedViewBox.frame.size

        // Create the bitmap context
        UIGraphicsBeginImageContext(rotatedSize)
        let bitmap = UIGraphicsGetCurrentContext()

        // Move the origin to the middle of the image so we will rotate and scale around the center.
        CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0, rotatedSize.height / 2.0);

        //   // Rotate the image context
        CGContextRotateCTM(bitmap, degreesToRadians(degrees));

        // Now, draw the rotated/scaled image into the context
        var yFlip: CGFloat

        if(flip){
            yFlip = CGFloat(-1.0)
        } else {
            yFlip = CGFloat(1.0)
        }

        CGContextScaleCTM(bitmap, yFlip, -1.0)
        CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage)

        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        return newImage
    }
}

Like I said, for ever 1-3 times it works perfectly, then every now and then a few images won't be rotated.

I've tried iterating through the array checking the image.imageOrientation. Which returns the same results Up, even if it's not Up.

Upvotes: 0

Views: 49

Answers (1)

Paulw11
Paulw11

Reputation: 114836

You are mutating the array from multiple threads at the same time as you are enumerating it. Access to an array is not thread safe so sometimes the change made by one thread is overwritten by another thread.

You should store your update image references in a temporary arrays and assign this to your property when you are done. This will avoid modifying the array as it is enumerated.

I also recommend that the updates to the temporary array are dispatched synchronously on a serial queue to avoid concurrent updates.

Upvotes: 1

Related Questions