How to get UIImage of AppIcon? - ios

I am using Assets Catalog, and adding app icon of various size to the assets is okay.
But when I tried to get the UIImage programmatically, it returned nil.
UIImage *appIcon = [UIImage imageNamed"AppIcon"];
The app icon is named AppIcon (the default), and the actual files are app-icon-256.png etc.
I also noticed that unlike normal images, app icons are in an "App Icon" set, in the directory AppIcon.appiconset. Normal images are in the directory someimage.imageset.

The problem is that the AppIcon from the asset catalog is not placed in the the catalog after compiling. Instated it it copied into your apps bundle, just like before.
The name conversion used when copying the icon to the app bundle is AppIcon<size>.png, where the size is for example 40x40 or 72x72
You can get your apps icons by specifying the size of the app icon you want:
UIImage *appIcon = [UIImage imageNamed:#"AppIcon40x40"];

The >iOS10 answer is:
Copy & paste this extension.
extension Bundle {
var icon: UIImage? {
if let icons = infoDictionary?["CFBundleIcons"] as? [String: Any],
let primary = icons["CFBundlePrimaryIcon"] as? [String: Any],
let files = primary["CFBundleIconFiles"] as? [String],
let icon = files.last
{
return UIImage(named: icon)
}
return nil
}
}
Then just call this:
Bundle.main.icon
SwiftUI:
Image(uiImage: Bundle.main.icon ?? UIImage())

Update Sep 12 2022: This doesn't work anymore, as of iOS 16.0.0 at least.
The methods of loading the main app icon highlighted in other answers like from Rufat Mirza used to work, and still does for debug builds, but I got an app rejection from Apple saying the app was crashing on launch. Turns out that the builds that contained this code started crashing on iOS 16, but only when installed via App Store/TestFlight (builds using the "Release" Configuration). What's more weird is that builds using the "Release" Configuration compiled via Xcode also wouldn't crash, only when uploaded to App Store and downloaded from TestFlight, so keep this in mind.
The fix was, unfortunately, to create a new Image asset with the same content as the AppIcon asset.
Note that this workaround still works for macOS as of the 12.5.1 and whatever macOS version Apple is using when reviewing their apps as of today, but since I already had to duplicate the asset for iOS, I also used the same asset for macOS to avoid this little hack :)

For those of us, who still need an obj-c version, I made a transcript of the relevant parts of the answer by Rufat Mirza:
NSDictionary *icons = [[NSBundle mainBundle] infoDictionary][#"CFBundleIcons"];
NSDictionary *primary = icons[#"CFBundlePrimaryIcon"];
NSArray *files = primary[#"CFBundleIconFiles"];
return [UIImage imageNamed: files.lastObject];

Related

UIImage(named: changes in xcode 8.1 adds case sensitivity?

My application was working fine with a set of images all in lower case, being accessed from the code using:
let image : UIImage = UIImage(named: "\(word.name)")!
the "word.name" returns a string with capitalized first letter. For example "Picture Of Something" for the image "picture of something.png".
I updated my iPhone to 10.1 which required me to update xcode to 8.1. After that my app is crashing - not being able to find the image.
I did try to update one of my images to "Picture Of Something.png" and it did display that image then failed on the next one where the case does not match.
As a workaround, I started using
let image : UIImage = UIImage(named: "\(word.name)".lowercaseString)!
Question is: Is this change listed anywhere in the API and has anyone faced this issue? If not, could it be a bug in 8.1 that needs to be reported?

loading user images works in simulator but not on the iphone xcode 6 Swift

Im trying to load(and upload) images in my app(by picture path).
This is working in my simulator. everything works there. only when im trying to do this on the iphone itself it won't work and i see just the empty UIImageviews.
The paths are loaded the same as in the simulator. And originate from:
PHImageManager.defaultManager().requestImageDataForAsset(asset, options: nil)
{
imageData,dataUTI,orientation,info in
cell.setString(info["PHImageFileSandboxExtensionTokenKey"] as String,name:dataUTI as String)
}
And the PHImageFileSandboxExtentionTokenKey is split into the data and the url when loading the image.
this results in the simulator as :
/Users/Twizzler/Library/Developer/CoreSimulator/Devices/3E671415-8B83-44DA-870F-19BF2BC11F8F/data/Containers/Data/Application/8872109F-3784-40EB-BEB6-4E9FDABE013D/Documents/1613945_10200645161051698_4122753901212984922_n.jpg
and in the iphone as:
/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG
Im loading the image like this:
let image = UIImage(named: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
in this case i put the image url hardcoded (this is in the final app an array of images)
I don't get an error or stack trace. When placeing a breakpoint im seeing the image information in the same way as the simulator
as suggested by the answer im now trying to load them as follows:
let image = UIImage(contentsOfFile: "/private/var/mobile/Media/DCIM/102APPLE/IMG_2607.JPG")
cell.imageView.image = image
This isn't working and i can't upload the files
That’s not how imageNamed works—as the documentation states, that looks for an image with the given name inside your app’s bundle. Try imageWithContentsOfFile.
Well i fixed it! after some puzzling days im now using this way to access upload and
cell.imageView.image = UIImage(data: array[indexPath.row][0] as NSData)
This shows the image. I can save the NSData in the CoreData and reload the image on this way.
To lighten the load on the system im using this:
cellData.checked = 1
var imageData = UIImageJPEGRepresentation(cell.imageView.image, 1)
self.array.append([imageData,cellData.imageData] )
let myObj : ViewControllerImagePicker = self.parentViewController as ViewControllerImagePicker
let textfield: UILabel = myObj.amountLabel! as UILabel
textfield.text = String(self.array.count )
cell.textLabel.alpha = 1
this code is being called when there is clicked on a cell. by setting the cellData.imageData i can recall the cells (when clicking back to the collection view)
I do not know if the way im doing it is correct or works with more that 10 files because of data usage problems. But in my case with a max of 6 selected pictures it works like a charm
The simulator works completely different than a real device when it comes to files, the app bundle and sandboxing.
For starters the simulator will let you write to and add or change files in your app bundle. iOS running on a real device won't let you do this.
You can't hardcode any paths in your app. Even if it works today or on your device in test mode that doesn't mean it will work on a released version. And even if it does it could stop working on any update. Apple several times has changed where things are stored and the path structure in the phone. And where you are allowed to write.
Make bundle calls to get the path locations of standard folders.
Use the assets library to load images from the photo library, or to save them there.
There are tons of resources and tutorials online on how to do this.

Swift playgrounds with UIImage

I am working with Xcode 6, and I'm trying to recreate the code demoed during session 401 "What's new in Xcode 6". I've added an image to Images.xcassets (called Sample) and within the playground file I'm trying to access this image, as demoed.
My code is as follows (like the demo):
var sample = UIImage(named: "Sample")
However, I can't get it to work like the demo. Am I missing something?
Look at the iOS Developer Library->Playground Help and search"Resource Files" and you will find the answer
1、Open the .playground
2、Show the Project navigator by selecting View > Navigators > Show Project Navigator.
3、Drag the images to the Resources
Like follow:
Open the .playground file in Finder.
Create a folder called Resources next to it.
Add any images you want to this folder.
In the playground press opt-cmd-1 to open the File Inspector. You should see the playground on the right. If you don't have it selected, press cmd-1 to open the Project Navigator and click on the playground file.
Under 'Resource Path' choose 'Relative To Playground'
Click the folder icon underneath and choose the Resources folder created earlier.
You should now have a bundle that you can use with the standard NSImage(named:"filename_without_extension"):
Note: Because Xcode will frequently overwrite the .playground folder, I recommend using this method so the resources folder isn't getting constantly deleted and re-created.
I had some trouble with this also.
Unfortunately, Chris' answer didn't work for me. I suspect perhaps a later beta release of Xcode 6 may have removed this setting.
Here's a solution as of Xcode 6.0 beta 4 (6A267N) available 21st July 2014. I would guess that this corresponds to the "Inside playground" option previously. That is where the Resources folder is within the playground package itself.
Here's how to set this up.
Using Finder - or if you're like me and use the awesome Path Finder - right select and choose Show Package Contents as follows:
That reveals the packages Resources folder:
Copying the image files into that folder will do the business:
let imageNames = ["back-button", "background", "bg_top"]
let images = imageNames.map { UIImage(named: $0) }
For Xcode 9:
Select Resources folder
Right click then "Add files to "Resources""
Use it like:
let image = UIImage(named: "no")
As of Xcode 8 Beta 1, you can use Image Literals to import an image into an Xcode playground:
Start typing image to add an image literal:
Select (or browse for) your image:
See your image inline:
However, I can't get it to work like the demo. Am I missing something?
I'm not sure where you need to put the image to refer to it using only the name, but I got the same code to work by specifying the full path to the image, like:
var sample = UIImage(named: "/Users/my_user_name/Desktop/Image1234.jpg")
Having to use the full path seems more complicated than it should be, but it works and it let me move on to more interesting problems.
You can find out the path of resourcePath using these commands in playground:
var bundle = NSBundle.mainBundle()
var path = bundle.resourcePath
Default for me was:
/Applications/Xcode6-Beta.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents
I had difficulty getting this setup for an iOS playground, as opposed to an OS X playground. Trying to do it using bundles and relative paths makes it more complicated.
If you just want to get your hands on an image quickly, you can also just use absolute file path:
On iOS:
# iOS
let absoluteImagePath = "/absolute/path/to/image.png"
let image = UIImage(contentsOfFile: absoluteImagePath)
And on OS X
# OS X
let absoluteImagePath = "/absolute/path/to/image.png"
let image = NSImage(contentsOfFile: absoluteImagePath)
This is what worked for me on Xcode Version 6.1.1.
Create Playground file under same directory as main storyboard.
Open Utilities pane for Playground file, and click the right arrow in Resource Path section to add your images in that directory.
Test image within Playground file.
On the iOS playground with XCode 6 beta 5 (and probably later) you can see the image inside the bundle:
In the playground press Cmd+Opt+1 and click the arrow under the Resource Path (this will open Finder)
Put your picture to this folder
Access it with either
let img = UIImage(named: "logo.png", inBundle: NSBundle.mainBundle(),
compatibleWithTraitCollection: nil)
or
let path = NSBundle.mainBundle().pathForResource("logo", ofType: "png")
let img = UIImage(contentsOfFile:path)
or in Swift 4:
let path = Bundle.main.path(forResource:"logo", ofType: "png")
let img = NSImage(contentsOfFile:path!)
Using XCode 6.3.1 and running playground in full simulator (iOS) I had to do the following:
Find your .playground file in finder
Right click it -> show package contents
If it doesn't already exist, create a folder named Resources inside the package
Add your image there
Then just instantiate with
let i = UIImage(named: "filename.png")
I have no idea why it is not working the easy way with PDF images.
I had to add this extension to load PDF images into my Playground:
extension UIImage {
static func fromPDF(_ url: URL) -> UIImage? {
var image: UIImage?
guard
let doc = CGPDFDocument(url as CFURL),
let page = doc .page(at: 1)
else { return nil }
let pageRect = page.getBoxRect(.mediaBox)
let renderer = UIGraphicsImageRenderer(size: pageRect.size)
image = renderer.image { ctx in
UIColor.clear.set()
ctx.fill(pageRect)
ctx.cgContext.translateBy(x: 0.0, y: pageRect.size.height)
ctx.cgContext.scaleBy(x: 1.0, y: -1.0)
ctx.cgContext.drawPDFPage(page)
}
return image
}
}
// Given the file "myImage.pdf" was added to your Playground's Resources folder.
let image = UIImage.fromPDF(#fileLiteral(resourceName: "myImage.pdf"))
It is based on this: https://developer.apple.com/forums/thread/90990

How can I load an image from Assets.car (compiled version of xcassets) within an NSBundle? (without using CocoaPods)

We're getting these kind of error messages:
Could not load the "iconStatus" image referenced from a nib in the bundle with identifier "com.company.OurResourceBundle".
Basically, we put a bunch of images in the xcassets folder ( which works for non-bundle loaded cases ). The xcassets and nib files are packed into a resource bundle.
When the app launches,
uiimageview in the nib file cannot load any images with the above error message.
[UIImage imageNamed:#"OurResourceBundle.bundle/iconStatus"] returns nil
The question is related to "How can I load an image from Assets.car (compiled version of xcassets) within an NSBundle?", but we don't use CocoaPods.
In iOS 7 it is not possible to load images from any .car file aside from the one that Xcode compiles into the main bundle. This was confirmed by an Apple Developer at https://devforums.apple.com/message/968859#968859:
Unfortunately it is not possible to load images from any car file aside from the one that Xcode compiles into your main bundle, as +imageNamed: does not accept a bundle parameter, which is what is needed to do so (and even then it would only be able to open a single asset catalog in a single bundle).
In iOS 8 there is a new method that appears to do what you want:
+ (UIImage *)imageNamed:(NSString *)name inBundle:(NSBundle *)bundle
compatibleWithTraitCollection:(UITraitCollection *)traitCollection
you have to define your bundle
imageView.image = UIImage(named: "iconName", in: Bundle.main, compatibleWith: nil)
I suspect if your image assets folder gets compressed into a .car file then NSBundle will know how to search for assets inside of it. Try creating a new bundle from your resources bundle. Then ask that bundle for the path of your image. Finally create an image from that path. This is sort of the approach we take when bundling image assets and localized strings with our static libraries. Our version is a little more involved as it takes care of things like #2x and ~ipad images automatically but this is the gist of it.
NSBundle *myBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:#"your bundle" ofType:#"bundle"]];
NSString *filePath = [myBundle pathForResource:#"icon" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:filePath];

iOS - UIImage imageNamed: returns null on device

[UIImage imageNamed:filename]
This method returns null only on the device.
I know it's known problem and it's usually due to the fact that simulator is case insensitive.
I have tried solutions proposed here: UIImage imageNamed returns nil
But nothing worked out for me.
The case is simple: I have 4 files named:Bar#2x~ipad.png, Bar#2x~iphone.png, Bar~ipad.png, Bar~iphone.png.
All of them are in project with target checkbox checked.
NSLog(#"%#",[UIImage imageNamed:#"Bar"]);
That line of code gives me null for device and I really have no idea what I'm doing wrong right now.
I did have such a problem recently too.
After playing with filenames and paths sometimes it helps when you clean and rebuild your project.
I found myself in the same situation recently.
The solution in my case was adding the extension to the file name.
[UIImage imageNamed:#"Bar.png"]
Completely clean your build and redo it:
delete the app from the device
option-clean the whole build directory in Xcode (⌘-Shift-K)
quit xcode
delete ~/Library/Developer/Xcode/DerivedData
restart xcode, build and run
This just happened to me, and to discover was very tough: I had one image which where nil just on device
logoWhite.png
my code:
[[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:#"LogoWhite"] forBarMetrics:UIBarMetricsDefault];
After a while of debugging, I noticed that the name of the image is beginning with capital case letter. Obviously this doesn't matter on OSX with a ignore case file system. iOs file system isn't, so the image worked on the simulator but not on the device.
I bet that all the solutions about cleaning derived data and rebuild did randomly end with renaming the image, and this would do the trick as well. Just posting here for future reference :)
I encountered this issue and just fixed it. I listed the solution below as a reference.
I have several images, and use [UIImage imageNamed:filePath] to show them. All of images displayed well except 1 on simulator/device, but all of them can be seen on OS X. For that image, [UIImage imageNamed] always return null.
After few minutes' investigation, I found that the image cause problem is far big in file size: 4.1M. Others are all around 800kb. They have nearly same size in dimension.
Then I try to open it in image editor, then re-save it. After this, the size dropped to 800k. problem solved.
The reasons I guess,
[UIImage imageNamed:filePath] has a max file size limit? (low possibility, but need to check official document)
the image itself has some error. But OS X has better tolerance than iOS. so iOS cannot read and return null. This issue is like OS X can play more types of video files than iOS since it support more codecs.
so if you encounter this issue in the future, take a few seconds look at the file size. Hope help.
This is an odd problem, which I hadn't seen until this week.
Below are my findings, and a workaround to your problem.
In my iPhone app, I download an image and store it locally, and this had always worked fine.
But now when I run the same code, it was suddenly failing to create a UIImage out of it using the imageNamed function, and now it was returning nil.
Three notes though:
This exact code did work before, using the same source code and .png image files. I'm not sure if my copy of XCode 6.x or iOS 8.x quietly updated itself in the meantime.
The code continues to work okay (with the same image file) on the iPhone simulator. It just doesn't work on a real device.
Take a look at the code below. When UIImage:imageNamed failed, I ran some code to check if the file actually existed.. and it did. Then I loaded the binary data from the file using NSData:contentsAtPath (which also proves that the file exists and was in the right folder), then created a UIImage out of that, and it worked fine.
Huh ?!
UIImage* img = [UIImage imageNamed:backgroundImageFilename];
if (img != nil)
{
// The image loaded fine (this always worked before). Job done.
// We'll set our UIImageView "imgBackgroundView" to contain this image.
self.imgBackgroundView.image = img;
}
else
{
// We were unable to load the image file for some reason.
// Let's investigate why.
// First, I checked whether the image was actually on the device, and this returned TRUE...
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:backgroundImageFilename];
if (fileExists)
NSLog(#"Image file does exist.");
else
NSLog(#"Image file does not exist.");
// Next, I attempted to just load the bytes in the file, and amazingly, this also worked fine...
NSData *data = [[NSFileManager defaultManager] contentsAtPath:backgroundImageFilename];
if (data != nil)
{
// ..and then I COULD actually create a UIImage out of it.
img = [UIImage imageWithData:data];
if (img != nil)
{
// We have managed to load the .png file, and can now
// set our UIImageView "imgBackgroundView" to contain this image.
self.imgBackgroundView.image = img;
}
}
}
As I said, this code does provide a workaround for this problem, but it's very odd that it's suddenly started happening.
And, I should say, I did try the other suggestions in this thread, cleaning the project, removing the DerivedData, completely removing the app from the device, and so on, but they didn't make any difference.
I would be interested in knowing if anyone else hits this issue, and finds that my code sample works for them.
Update
I'm an idiot.
I'm not sure if the UIImage:imageNamed function has changed or something (and if so, why it continues to work okay on the iPhone 8.1 Simulator), but I found the following one line does work okay:
UIImage* img = [[UIImage alloc] initWithContentsOfFile:backgroundImageFilename];
So it seems as though you should use this function for loading images which aren't a part of your app's bundle.
I also have same issue then : XCode - Build Phases - Copy Bundle Resources -{see image is available or not}- add{image} - clean - delete app - Run .
I would like to add one more important point to all the above solutions
Make sure you add your image resource to right target
By mistake if Developer mess-up link with resource and target then conditions arise.
if you have multiple target then double check the resource are set to correct target.
Attached screenshot example in case of resource link between multiple targets.

Resources