Goals:
Programmatically load first image (approx 94kb) into an ImageView in the main storyboard from the Assets.xcassets folder (see code below) - works perfect
Then when you load a second image (same size) into the original UIImage it causes the iOS app to crash.
Here is my code:
mainImageView.image = UIImage(named:"FirstImage.png") // load first image, no issues
Then if you programmatically load a second image into the same UIImage it causes the device to throw a low memory warning and the iOS crashes the app:
mainImageView.image = UIImage(named:"SecondImage.png") // load second image
After reading a number of answers on SO and other articles (see below), the best way to manage memory when you are loading multiple images into an animation array is to use the contentsOfFile: imageName instead of the UIImage(named:"FirstImage.png")
See Article here:
http://www.alexcurylo.com/2009/01/13/imagenamed-is-evil/
And secondly Apple states the following:
If a matching image object is not
already in the cache, this method locates and loads the image data
from disk or from an available asset catalog, and then returns the
resulting object. The system may purge cached image data at any time
to free up memory. Purging occurs only for images that are in the
cache but are not currently being used. In iOS 9 and later, this
method is thread safe. Special Considerations If you have an image
file that will only be displayed once and wish to ensure that it does
not get added to the system’s cache, you should instead create your
image using imageWithContentsOfFile:. This will keep your single-use
image out of the system image cache, potentially improving the memory
use characteristics of your app.
https://developer.apple.com/documentation/uikit/uiimage/1624146-init
Lastly, upon receiving the Memory Warning you could also create the following function:
func applicationDidReceiveMemoryWarning(application: UIApplication) {
NSURLCache.sharedURLCache().removeAllCachedResponses()
}
Hope this helps someone else :)
I've created a small photo gallery which is presenting a new view controller with a larger version of the photo and some additional text when it is clicked:
The problem is - after going through a handful of images - the application crashes due to overuse of memory. I attempted to resolve this by compressing the images in order to leave a smaller memory footprint, but the issue remains and I'm not sure what else I can do to resolve this issue.
Also - there is almost no code to doing this since I'm using storyboard's push segues as well as the built in navigation item to go back between viewControllers.
P.S.
If you feel source code is necessary to provide insight in this instance - it can be found here:
https://www.dropbox.com/s/q1qq8pq4tzv8wyo/EXAMPLE%20BUILD.zip?dl=0
To resolve this issue you have to use this trick; Put a "placeHolder" image in your cell's imageview in "StoryBoard". Don't load the images all at once in your "ViewController", load them one by one by running a loop or in your "cellForRowAtIndexPath()" method and add a delay in each iteration (Load first image then add a delay, load second image and add a delay, then for third one and so on up to the last image).
If you want to know how to add a delay then check this link:
NSTimer - how to delay in Swift
To resolve this issue I simply resized the images - I noticed I accidentally used a gigantic (6000 x 4000) image and even though I compressed the images iOS had to crunch pretty hard to resize them into the view... thereby causing the memory leak and subsequent crash.
Resizing them to 600x400 did the trick.
I have noticed that if I change an image in the xcassets, the launch storyboard does not update.
For instance, let's say you have a UIImage view in your launch storyboard with an image called "logo" that is blue. If you open up the in the Finder and change the color of the image to red, next time you run on the device the logo will still be blue.
The preview of the storyboard in xCode will show the correct (red) logo image.
Before running, I have tried:
Cleaning the Project
Deleting Derived Data
Deleting the App
Renaming the Image
Nothing seems to fix the problem. Is there another option that I am missing?
Appears to be a problem with caching on the device. Delete your app, restart the device, and pray. Image does not update when changed if that image is used on LaunchScreen.storyboard
Exiting out should normally solve the job... Sometimes, especially in the playground I have heard and experienced, it will not automatically refresh and you can either:
Wait a tiny bit(in most cases) but it seems you would not be asking if it were a few seconds of delay so maybe try
Deleting everything associated with that image(the outlet reference, image on storyboard, and any time you use that image in you code(leave those spaces blank)), then create a new UIImageView and assign it to your desired image.
In your Images.xcassetts file you may have only changed the info on one of the sizes; make sure those are all set.
Then again, especially after the most recent WWDC, there have been some bugs in Xcode that will need to be patched in the future. At the least, I hope this helps you and people who view this in the future.
I tried deleting the app from device while also deleting the derived data and cleaning, but it seems that you have to restart the device. That is the only thing that worked for me.
I have a method, and in this method, there is this conditional:
if (self.sleepingCharacter.objectSprite.image == [UIImage imageNamed:#"sleepingRight.png"])
{....
This normally works fine. But I've noticed, in the iOS simulator, that when I put my App in the background by pressing command-H, and then i bring my app back, this conditional no longer works. Do you know why this would happen?
I tested to see if the code would work if I wrote this:
if (self.sleepingCharacter.objectSprite.image)
{....
And it did work, which means that there is still an image there. Now I am confused.
You are using the == operator to compare the two images. This will only be true of the two images are actually the same hunk of memory (the same pointer).
The UIImage imageNamed: method caches images. So in theory if you call it again and again for the same image name, you will keep getting the same pointer and your code appears to work.
But the image cache can get purged at times due to memory usage. Once the image gets purged, the next call to imageNamed: will return a new image pointer and your check will fail.
You need a better way to see if the two images are the same. One solution is to convert both images to NSData objects using UIImagePNGRepresentation then compare the two NSData objects using the isEqual: method.
I am pretty new to iOS and Xcode.
I tried to load an image with
[UIImage imageNamed:#"imageName.png/jpg and so on"];
but it only returns nil. The image should be in my project bundle, considering the fact that I can choose it from drag and drop menus in the InterfaceBuilder and it was added to Xcode via the "Add files to "projectname"..." menu.
It makes no difference whether I use .png or .jpg images, the result stays the same: they work via IB but not if I try to run the imageNamed method myself.
There are only a few reasons why an image would come back nil with imageNamed:
The image is not in your bundle. Make sure the image is actually in your project. Make sure the target is checked by clicking on the file and selecting the target it belongs to.
You have the image name spelled incorrectly or a problem with the extension.
You are using a retina display but do not have an #2x image. Try changing your simulator to retina and see if it shows up.
If you are using an asset catalog make sure you have the correct devices selected in the attribute inspector.
Some tips:
If you are testing using simulator delete the app off of your simulator and clean your project, then re-run. If it still shows up it should show up on your phone (if it doesn't it's probably an issue with the case of the filename or the #2x version).
If you are testing on your phone and it doesn't show up, make sure you are using the same version of the simulator (if you have an iPhone 4/4s make sure to use the 4/4s simulator with retina).
One last thing according to this post: JPG image doesn't load with UIImage imageNamed There is some issue with certain JPG types working with imageNamed and no extension. IMO, you should be using PNGs anyway since iOS compresses them for you, unless you just have to use JPG.
Re Mike Weller's comment. The checkbox is ....
If you verified all of the above and are finding that your UIImage(named: "myImage") returns nil from code inside of a dynamic framework you are building, then you have to change the code to:
UIImage(named: "myImage", in: Bundle(identifier: "com.myframework.name"), compatibleWith: nil)
This should retrieve the asset from CXAssets correctly.
In my case, the PNG was malformed.
For some reason Xcode preview shown it correctly, but when I tried loading it with UIImage, it returned nil.
I just had this issue for jpg files named on disk "file.jpg"
I was trying to load without the extension, just #"file". While this works fine for pngs, it does not for jpg. Once I used #"file.jpg", it worked!
Swift 5
If you get UIImage nil in dynamic framework, you should set image with bundle identifier.
You can create an extension to Bundle like this;
Create an extension;
extension Bundle {
public static let myFramework = Bundle(identifier: "com.myFramework.bundle")
}
Then you can use like this;
UIImage(named: "myImageName", in: Bundle.myFramework, compatibleWith: nil)
Or
You can use like this;
UIImage(named: "myImageName", in: Bundle(for: type(of: self)), compatibleWith: nil)
I think the first one is more useful because it's more readable than second one.
Try re-exporting your image.
I had a similar problem, UIImage imageNamed was returning nil and none of these answers fixed my problem.
I found out that it was actually something wrong with the png file. I opened the file in GIMP image editor, saved it as a new file, exported it again as png and magically it started working.
I didn't change anything in code at all so there was definitely something wrong with the actual image file.
try
[UIImage imageNamed:#"imageName.png"];
instead (with an extension)
I had the same problem: #"photo.jpg" resulted in 'nil' UIImage.
Changing to the "actual" filespec, #"photo.JPG" works fine!
I hadn't realized there was case-sensitivity there! VERY non-intuitive.
i had a similar issue, finally the cleanup fixed it: the image showed up in the simulator, but id did not show up when running the app on the iPhone.
What I did:
1) deleted the app from the iPhone
2) performed Product/Clean
after that the bug was fixed and the image showed up!
Try to use UIImage(contentsOfFile:) instead of imageNamed. It worked for me with downloaded images.
Check that file has no space at the end.
The name like name #2x.png will fail loading, but name#2x.png is fine
Does the image work on the simulator but not on the device?
If so, in this scenario it is always to do with the case of the name. The device requires exact case and the simulator is not so fussy if I remember correctly.
e.g. for an image named image.png
[UIImage imageNamed:#"Image"];
would work on the simulator but not on the device...
Make sure you have the image for the DEVICE you are using in your .xcassets file. An image flagged for iPad won't show up on the phone (or the simulated phone).
In addition to #Inturbidus's answer:
For those who came here working on Application Extensions:
The image you are working with should belongs to both targets - hosted app and extension.
In other case you'll always getting nil trying to access it from within the extension's code.
For Xcode 6.4, click on Images.xcassets and check whether there are entries for each image that you called. You may right-click on the image and select "Show in Finder" to check if the images are the correct ones added.
Make sure the Attributes Inspector name field of the image matches exactly the name you're using. In my case the image was part of a folder and so the image name was "folder/name". Using this long name solved the problem. XCode 7.3.1
In my case, using a name with accented characters proved to be a poor idea. I changed Astéroïdes to Asteroids and it worked fine.
In my case problem was with image name in asset catalog.
For example if you have image with name "TEst" and change name to "Test", changes won't be indexed. If your teammate will pull commit with this changes, image in his asset catalog will have previous name "TEst".
Very small chance to catch this situation but it's possible.
I had multiple .xcassets in my projects and 2 had duplicate name of images. So it was not loading the image in my case.