Memory warning while load image in UIImageView in Swift - ios

I have a viewController with an UIImageView, I change image when slide with Swipe.
While I change some images, I received memory warnings and App crash sometimes. Images have 300KB aprox...
I load images with:
image1.image = UIImage(named: "myImage")!
How can resolve this? In Swift haven't release.. How can do this?
Thanks!

The problem here is the Method,
[UIImage imageNamed: ];//In objective c
image1.image = UIImage(named: "myImage")! //in Swift
This itself is a very memory using method. instead of this use:
init?(contentsOfFile path: String)

Related

Memory issue decodeObjectForKey (Swift project)

Within an Swift application exporting the individual single viewController images (using the drawViewHierarchyInRect).
For each viewController I recover the contents of imageViews as follows:
self.imageView = (aDecoder.decodeObjectForKey("imageLevel") as? UIImageView)
self.imageView!.contentMode = UIViewContentMode.ScaleAspectFit
self.imageView!.multipleTouchEnabled = true
self.imageView!.autoresizesSubviews = true
self.addSubview(imageView!)
After 15 "page": crash. If I comment these lines, the code works again. Is there an alternative to decodeObjectForKey?
I'm not really sure what you're doing here, but you shouldn't be trying to encode a UIImageView and save it off as the view is tied to other items. You could encode the UIImage instead. Your UIImageView should come from your storyboard/xib and then you set the image you decoded to the UIImageView.

Unable to add UIImageView Xcode Swift

For some reason I am unable to add a UIImageView to my app. This is the code I am using and I have searched for quite a while to figure this out but haven't had any luck.
super.viewDidLoad()
let cloudimage = UIImage(named: "cloud")
let cloudView = UIImageView(image: cloudimage)
self.view.addSubview(cloudView)
cloudView.frame = CGRectMake(0,0,100,200)
The image is a .png in my assets folder so I don't think it's that. I do have auto layout settings enabled if that is an issue? I know it can be an issue with moving a UIImageView around by using its frame, but I think I should still be able to place the image in the View no problem with this code.
I am not quite sure what to do any suggestions would be great, this is extremely frustrating.
If your image is nil, your UIImageView will not render anything. Try debug your view hierarchy.
https://developer.apple.com/library/tvos/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/special_debugging_workflows.html
http://www.raywenderlich.com/98356/view-debugging-in-xcode-6
you need to add UIimageview to main view.
self.view.addSubview(cloudView)
Try by giving the image extension also while setting to UIImage
let cloudimage = UIImage(named: "cloud.png")
let cloudView = UIImageView(image: cloudimage)
cloudView.frame = CGRectMake(0,0,100,200)
self.view.addSubview(cloudView)
Checked and its working.

Slow UICollectionView with asynchronous loading

I have an UICollectionView which loads images of the iPad's memory and displays them in a grid,like Apple's Photos app. The UICollectionViewCell loads thumbnails asynchronously:
func setImage(img:String){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//load the image in the background
let image = UIImage(contentsOfFile: img)
//when done, assign it to the cell's UIImageView
dispatch_async(dispatch_get_main_queue(), {
if let imageView = self.imageView{
imageView.image = UIImage(contentsOfFile: img)
}
})
})
}
However, while scrolling the view lags as if it is waiting for the images to load, especially with Retina graphics. The cells and images are about 240x180px big. Is there anything wrong with the image loading above or further optimisations need to be made?
UPDATE: Time profiler results
You've already found that you're loading the UIImage again on the main queue; fixing that will help.
UIImage lazy loads its internal image data in most cases. One trick is to call its CGImage property while still on the background queue to force it to actually create its internal image data instead of lazily loading it when the image view is drawn the first time:
func setImage(img:String){
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//load the image in the background
let image = UIImage(contentsOfFile: img)
image.CGImage // <- Force UIImage to not lazy load the data
//when done, assign it to the cell's UIImageView
dispatch_async(dispatch_get_main_queue(), {
if let imageView = self.imageView {
imageView.image = image
}
})
})
}
Note: If you have a lot of images you may end up getting a memory warning fairly quickly doing this. If you do, this probably won't help because the memory warning will typically cause UIImage to clear its internal image data again to free up resources.
On the line
imageView.image = UIImage(contentsOfFile: img)
I was loading the image again on the main thread, not the image loaded asynchronously. Changed to
imageView.image = image
Scrolling is a bit better, but yet choppy. The time profiler shows similar results as before. May the bottleneck be in the UIImageView drawing? It works fine with non-retina thumbnails.
The bottleneck was that some thumbnails were scaled improperly and were a lot bigger than the UIImageView, which caused the longer loading time. I also presume this caused slower drawing since the UIImage had to be downscaled to fit in the UIImageView.
I fixed the thumbnail-generating code and scrolling is smooth again.
P.S. I also fixed the misplaced UIImage(contentsOfFile: img) variable in the initial code, see my other answer.
in Swift:
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let imagem = UIImage(named :"image")
dispatch_async(dispatch_get_main_queue()) {
cell.IMG_Novidades.image = imagem
}
}
//THIS IS VERY IMPORTANT
cell.layer.shouldRasterize = true
cell.layer.rasterizationScale = UIScreen.mainScreen().scale

Generating the image on the screen in IOS Simulator

so what I currently wish to accomplish is for an image to be printed on the background of the IOS simulator screen, so inside of my viewDidLoad, I have this
var img = UIImage(named: "paper.jpg")
This can create the image variable, but I haven't found how to display it on the screen yet. It may seem like a trivial problem, but I haven't found any documentation on this online after searching for awhile. Thanks for reading.
Refer to the UIColor documentation.
In Swift, you have to call a convenience initializer. This is because in Swift, all Objective-C class methods which return an instance of their class become convenience initializers.
Here's how it looks in Swift:
self.view.backgroundColor = UIColor(patternImage: UIImage(named: "paper.jpg"))
+ (UIColor *)colorWithPatternImage:(UIImage *)image returns a UIColor instance, so it will become a convenience initializer in Swift. Similarly, UIImage imageNamed: becomes init(patternImage image: UIImage!).
since this is the marked answer, I felt the need to add a bit more code for completion.
as #senior has posted in his answer another way to add an image to your background is by the use of adding a UIImageView as a subview like so:
let img = UIImage(named: "paper.jpg")
let imgView = UIImageView(image: img)
self.view.addSubview(imgView)
You have to add your image to an ImageView and add this to the current view as a subview,
let img = UIImage(named: "paper.jpg")
let imgView = UIImageView(image: img)
self.view.addSubview(imgView)

Flip UIImageViews for Right to Left Languages

iOS automatically flips the entire ViewController when using a RTL language like Arabic and does a great job with most of the layout, especially text. The default behavior is to flip the layout but leave UIImageViews the same orientation (since you generally don't want to reverse images).
Is there a way to specify that some images should be flipped (such as arrows) when the phone is set to a RTL language?
iOS 9 includes the imageFlippedForRightToLeftLayoutDirection method that you can use, that automatically flips the image in a UIImageView when in an RTL localization.
The best solution I found to date is marking the image in the assets file as mirror.
We can use imageFlippedForRightToLeftLayoutDirection which returns flipped image if current language is RTL(right to left). i.e
Objective-c
UIImage * flippedImage = [[UIImage imageNamed:#"imageName"] imageFlippedForRightToLeftLayoutDirection];
Swift 3
let flippedImage = UIImage(named: "imageName")?.imageFlippedForRightToLeftLayoutDirection()
Source: Apple Docs
You have to manually flip the UIImages in the UIImageViews you want when the phone is set to a RTL language. This can be easily achieved with this code:
UIImage* defaultImage = [UIImage imageNamed:#"default.png"];
UIImage* flipImage = [UIImage imageWithCGImage:sourceImage.CGImage scale:1.0 orientation: UIImageOrientationUpMirrored];
myImageview.image = flipImage;
I ended up using localized images for the forward and back arrows. This had the advantage of not having to add code each place the image was used and gives the opportunity to clean up the arrows if there are gradients that don't work well flipped.
While we wait for iOS 9 improved right to left support you could create a UIImageView subclass and override setImage to mirror inside the images as #nikos-m suggests and calling super.image = flipImage.
That way you can easily set all the images views you want to flip using custom classes in Interface Builder instead of having to add IBOutlets.
Swift 5
If you want to individualize the image flip, you can register each image with the direction you want since the layout direction is a trait:
let leftToRight = UITraitCollection(layoutDirection: .leftToRight)
let rightToLeft = UITraitCollection(layoutDirection: .rightToLeft)
let imageAsset = UIImageAsset()
let leftToRightImage = UIImage(named: "leftToRightImage")!
let rightToLeftImage = UIImage(named: "rightToLeftImage")!
imageAsset.register(leftToRightImage, with: leftToRight)
imageAsset.register(rightToLeftImage, with: rightToLeft)
This is the same as configuring it in the asset catalogue as #SergioM answered.

Resources