Interface Builder: Choose media based on target - iphone

In Xcode I use targets to release several apps versions which share some base code and tend to have different graphics.
i.e. Pretending I have target JOHN and target DOE. I could add different images named exactly example.png to the bundle, and have each one targeted respectively. The code does not need any changes this way.
UIImageView *image = [UIImageView alloc] initWithImage:[UIImage imageNamed:#"example.png"]];
If instead I named each image per different version I would end up with something similar to this:
NSString *imageName;
#ifdef JOHN
imageName = #"johnExample.png";
#else
imageName = #"doeExample.png";
#endif
UIImageView *image = [UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]];
Having several versions and many images this quickly becomes messy and having a huge file with constants looks to me like an overkill, so I end up with the first option.
The problem is:
While working on nibs files, Interface Builder just appears to load example.png randomly. So if I'm working on target JOHN it's an annoyance that IB just decided to load example.png from the DOE target.
There's any way for Interface Builder to load media based on a target?

Just to close this question, the answer is: no.
As of Jan '11, you can't load media based on a target on Interface Builder, but you could use some workarounds, as Digital Robot and my own description in the question pointed out.

why not have this define at the beginning of the code
#ifdef JOHN
#define APP #"john"
#elseif DOE
#define APP #"doe"
#endif
and then, every time you want to use this, you may have...
imagename = [NSString stringWithFormat:#"%#Example.png", APP];

That should work. This may be new because some time has passed and I just learned that recently. Don't know wether this was possible ages ago when you acutally asked this question :) But it may be useful for others searching for a solution.
When adding a target to a project within xcode then it creates a subfolder in the file system. There is one subfolder for each of the taragts. The basic idea is, as far as I understand it, that all commonly used files are on the upper level in the project main directory and those that are individual to each target are in their respective directory.
(A bit like localized versions of files.)
So you may put the image of John as example.png in /project/john and the image of Doe as example.png in /project/doe.
You should double check that the correct versions of each image are included in the build settings for each of the targets respectively. (Copy Boundle Resources)
Doing so "example.png" is included only once in the boundle. Randomly loading of one image or the other should not longer happen, although you refer to it as "example.jpg" within your code.

Related

Images disappear after app released to appstore

There is something very weird in my app after it has been released to the appstore.
Some of the UIImages i used are just missing and seen black from some reasons.
I have checked many times before in device and simulator and it appeared just fine.
Some notes:
I did drag the files and check COPY - the images are in the library for sure
Images DO appears in Copy Bundle Resources under Build Phases
I used these 2 lines in order to get the image:
[UIImage imageNamed:#"email_icon.png"] and [UIImage
imageNamed:#"facebook_icon"]
And i have just noticed that the extensions of the images are PNG not png - maybe is that the reason?
Appreciate your assistance!
Can you replicate this issue on your device? If not I'd recommend deleting the current version from your device and redeploying. You may have cached images on your device which are not allowing you from seeing the issue.
Secondly, yes, filenames on the device are case sensitive. Also make sure that you are properly naming the files and it is not simply a spelling mistake or change from an image name.
Per your line of code you are missing the file extension on the second image
[UIImage imageNamed:#"email_icon.png"] and [UIImage imageNamed:#"facebook_icon"] <-- what type of file is facebook_icon?

How to develop iOS app with different sets of graphics under Xcode 4.2?

I have this app with one whole set of images, but I would like to add for example personalized set of graphics. Is there an easy way to organize and develop source code and not to get lost while switching between these sets of images?
One way I see it is to have on my hard drive two folders with graphics and before releasing replace in project current images with personalized set... is there a better way?
I'm using Xcode 4.2 and iOS 5.0 for this app.
Probably the easiest and most reliable in terms of maintainance is to write your own image access function or marco, that is controlled in one place globally. Then use this in all cases where you want to have the flexibility for differnt images for example like this. I just got used to this way of assigning an image with stretchableImageWithLeftCapWidth because it adjusts the size nicely.
Of course you may use any other way to assign your images, like directly without use of stretchableImageWithLeftCapWidth
Anyway, this is my suggestion:
NSString *s = [NSString stringWithFormat:#"%s%i",#"imageName",CONST_VERSION];
UIImage *theImage = [UIImage imageNamed:s];
myImageView.image = [theImage stretchableImageWithLeftCapWidth:12 topCapHeight:0];
and you can do
#define CONST_VERSION 1 // or 2
Then name your images like:
myImage1.png
and
myImage2.png

jpg images in iphone and 2x images

I am working on an iphone app and targeting iOS 4.0 or later. I am trying to add an image to UIImageView, and image is in jpeg format. This is what I have done so far..
UIImageView *bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 246.0)];
bgImageView.image = [UIImage imageNamed:#"background"];
[self.view addSubview:bgImageView];
[bgImageView release];
I have added two images,
background.jpg (as normal 1x image)
background#2x.jpg (for 2x / retina
display).
But when I build and run, everything runs fine, except there is no background. All my other widgets are there, but there is a white background and image is not showing.
Next I created two png images for my background, added it to the project and ran. This time my background was shown. I was perplexed because according to documentation jpg image can be used in iphone with UIImage.
I tried again with my jpg images and changed the code above to this
UIImageView *bgImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 246.0)];
bgImageView.image = [UIImage imageNamed:#"background.jpg"]; //added extension
[self.view addSubview:bgImageView];
[bgImageView release];
When I run the above code, background image is showing, but 2x images are not loaded. That shows my jpg image is fine, and it is not the culprit. So when I just give image name without extension, png files (both 1x and 2x)are loaded on respective devices, jpg files are not loaded at all.
Looks like a bug (either in sdk or documentation). iOS 4 is here for a good year. why no one noticed it? Also is there any option for me other than to convert all my images to png?
EDIT :
Well, two days in to the question, zero answers. I have already converted all my images to png, and that part of my project is done (as my project couldn't wait..). Still, for my own sake and for sake of everyone who faces this in future, I would like to know more about this problem. At least someone can confirm that this is indeed an apple bug. I am starting a bounty so that more people can see this thread.
EDIT AGAIN
2 days remaining for this bounty to end. Thanks for everyone who responded. But let me clarify one thing. I have already said that I have converted all my images to png and I moved along. I just wanted some confirmation that imageNamed treats jpg and png files same way. Documentation certainly says it will(unless Apple has written it somewhere other than UIImage documentation). If documentation is correct then my code failed me because of two possible reasons
It is a bug in imageNamed. If this is the reason, then I dont have too much option other than file a bug report, change my images to png or write a wrapper(like Chandan has said in his answer) and move on..
There is some problem with the jpeg image I used. Well I am not a photoshop guy. But I used
RGBA jpg image. If image does matter I am ready to ask my designer
friend and provide more info.
One more thing. This post also just tells about this problem. But he dont know the reason behind. So I am not alone.
EDIT : THE END
Well it is something related to the image itself. I googled and downloaded some sample jpeg images and played with it. Some of them shown up correctly and some doesn't. Since the boundy time is up, I am giving the boundy to PengOne who tried to reproduce the bug and successfully loaded jpg image without extension, there by making me to work with more images. Thanks for everyone who tried to help.
According to the UIImage Class Reference:
Discussion
This method looks in the system caches for an image object with the
specified name and returns that object if it exists. If a matching
image object is not already in the cache, this method loads the image
data from the specified file, caches it, and then returns the
resulting object.
On a device running iOS 4 or later, the behavior is identical if the
device’s screen has a scale of 1.0. If the screen has a scale of 2.0,
this method first searches for an image file with the same filename
with an #2x suffix appended to it. For example, if the file’s name is
button, it first searches for button#2x. If it finds a 2x, it loads
that image and sets the scale property of the returned UIImage object
to 2.0. Otherwise, it loads the unmodified filename and sets the scale
property to 1.0. See iOS Application Programming Guide for more
information on supporting images with different scale factors. Special
Considerations
On iOS 4 and later, the name of the file is not required to specify
the filename extension. Prior to iOS 4, you must specify the filename
extension.
Since you're targeting iOS 4.0 and later, you should not need the filename extension. I tried to reproduce this potential bug, but it worked as expected for me without the filename extensions.
Here are some ideas for what may have gone wrong to create this effect in your app:
It's possible that the problem comes from the cache if you changed your images at some point.
If you choose not to use the filename extensions, and you have both "background.jpg" and "background.png" as options, the preference appears to be to use the ".png" file.
If you set the target to iOS 4.0 and later after first running the app, then the filename extension would have been required and the image may have been cached blank, which leads back to theory 1.
That's the best I can make of this.
Write a wrapper to get the image like
-(UIImage*) getImage:(NSString*)imageName{
UIImage *image;
if ([[UIScreen mainScreen] respondsToSelector:#selector(scale)] == YES && [[UIScreen mainScreen] scale] == 2.00) {
// RETINA DISPLAY
NSString *jpegFile = [imageName stringByAppendingString:#"#2x.jpg"];
image = [UIImage imageNamed:jpegFile];
}
else{
NSString *jpegFile = [imageName stringByAppendingString:#".jpg"];
image = [UIImage imageNamed:jpegFile];
}
return image;
}
And from your code call
bgImageView.image = getImage(#"background");
With the dawn of Xcode 6 I have found that JPG images might not render at all on certain iOS7 devices (they may work on some but not on others, or they may not work on any, and you may see a different result on a different developers machine, there doesn't seem to be any consistency). This is regardless of whether the image is just referenced in UIImageView in a XIB or programmatically with [UIImage imageNamed:] (which returns nil).
After scratching my head for a long time, the solution was to rename the *.jpg file extension to *.png (whilst obviously leaving the file contents as JPG data).
HTH
You just need to provide the full name of image.
bgImageView.image = [UIImage imageNamed:#"background.jpg"];
don't leave off the extension.
As for the #2x, it is not necessary to call it out anywhere in the code. If you code correctly there is no need to test for a retina display as some here have suggested.
You can use jpgs, just tried it myself and it worked. Only suggestion is how you are instantiating it.
Try it this way:
stockImage = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"Morbo.jpg"]];
stockImage.frame = CGRectMake(0,0, self.view.bounds.size.width, self.view.bounds.size.height) ;
[self.view addSubview:stockImage];
This is the image I used:
http://futurama.wikia.com/wiki/File:Morbo.jpg

App failing to see #2x images

This is driving me nuts. Been searching for 2 days, and I can't find any real solution or explanation for why this is happening. I know there are threads here on SO, as well as some other places, but they have been no help. I have read the Apple documentation on the matter.
I have normal and #2x images in my app. They are named correctly (edit_image.png, and edit_image#2x.png). They are sized correctly (normal is 60x60, #2x is 120x120). They are both being copied into the app bundle, and when I examine the contents, I can see them both in the root.
I am grabbing the image by calling [UIImage imageNamed:#"edit_image"]. It never grabs the 2x image. It only sees the 1x image. However, if I check the scale first, and use this code:
if ([[UIScreen mainScreen] scale] == 1) {
NSLog(#"test");
editImage = [UIImage imageNamed:#"edit_image"];
} else {
editImage = [UIImage imageNamed:#"edit_image#2x"];
}
Then it does grab the correct image. I have tried everything. I deleted the high res from the project, cleaned, re-added the high res, cleaned and then built, no dice. I deleted all the images, and re-added them, no dice. I have done everything I can think of. What the hell is going on here?
Are you creating universal application for both iPhone & iPad. If universal app is there then you need to create 3 set of images:
1) edit_image~iPad.png
2) edit_image~iphone.png
3) edit_image#2x~iphone.png
each with the same resolution of 72 pixels/inch. While you need to provide double size for that #2x image which I think you've already done this.
Now, try the below code
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"edit_image" ofType:#"png"];
UIImage *image = [[UIImage alloc] initWithContentsOfFile:filePath];
Important: When creating
high-resolution versions of your
images, place the new versions in the
same location in your application
bundle as the original.
Source: http://developer.apple.com/library/ios/#documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/SupportingResolutionIndependence/SupportingResolutionIndependence.html
Two silly mistakes that I've made that can cause this problem:
Accidentally naming the small
versions #2x instead of the large
ones
Having the large versions be
slightly missized (by one pixel)
You don't need to add the "#2x" bit, or have the if-else logic at all. Just use [UIImage imageNamed:#"edit_image"].
I was suffering from the exact same problem, and finally found a solution (after 2 days of searching).
In my case the name of the #2x image didn't exactly match the normal sized image: tileSet.png and tileset#2x.png.
What made this so difficult to discover is that the #2x file did have the correct name in Finder and in XCode. I was only able to discover the problem by opening the image in Preview and looking at the Inspector. I don't know enough about the Mac file system to explain how this happens, but once I renamed the file to gibberish, then renamed it back to tileSet#2x.png everything started working as expected.

How do I go about including the Tortuga 22 NinePatch library to my XCode project?

First of all, there is finally NinePatch support for the iPhone, BIG thanks to the Tortuga 22 team for that. Unfortunately for me I have not been able to add their library to my project.
What is NinePatch?
The Tortuga 22 blog post.
The source code at git hub.
If I just drag and drop the source-files into my project I get a ton of "No such file or directory"-errors. If I reference the libNinePatch.a-file as an external framework I get the same result.
What is the proper way of doing this? There are no instructions from their part so I guess there must a fairly straight forward way of doing this.
Thanks in advance.
//Abeansits
I just like to tell everyone still struggling with this that I've uploaded a podspec to CocoaPod's repository.
This means that if your project uses CocoaPods (and why wouldn't it?), you can just add:
pod 'Tortuga22-NinePatch'
To your Podfile and you'll have NinePatch support. (notice it's still not ARC-compatible, pull requests are welcome!)
I know this is an old question, but just to help people that are searching for ninePatch in objective c, I want to inform that the UIImage class from ios 5 on, have a method to do what ninePatch do.
From UIImage reference:
Discussion
You use this method to add cap insets to an image or to
change the existing cap insets of an image. In both cases, you get
back a new image and the original image remains untouched.
During scaling or resizing of the image, areas covered by a cap are
not scaled or resized. Instead, the pixel area not covered by the cap
in each direction is tiled, left-to-right and top-to-bottom, to resize
the image. This technique is often used to create variable-width
buttons, which retain the same rounded corners but whose center region
grows or shrinks as needed. For best performance, use a tiled area
that is a 1x1 pixel area in size.
Availability Available in iOS 5.0 and later.
Declared In UIImage.h
An example of use if you want a image with a fix top:
UIImage* image = [UIImage imageNamed:#"YourImage.png"];
image = [image resizableImageWithCapInsets:UIEdgeInsetsMake(25., 0, 0, 0)]
Hope it help.
You should be able to add the files to your project. Answers to this SO question may help.
Also, be aware that UIImage does provide stretchable images. See -stretchableImageWithLeftCapWidth:topCapHeight: for details. That won't help you if you need to read images in actual nine patch format, perhaps for sharing resources with an Android app, but it's often all that's really needed.
Are you #include-ing the main header file(s) in whichever classes you need them or in the prefix.pch file?
If you download their source package from GitHub, you'll see that they've included an example project, NinePatchDemo. Inspecting this should give you all the information you need.
You'll see that they just dropped the NinePatch Xcode Project into the NinePatchDemo project, under "Other Sources". You can drag and drop the NinePatch project into your own in the same way. You can check the build and target settings to make sure you're including any paths/libraries that you need in order to build.
It looks like you want -all_load -ObjC in Other Linker flags for your target, and if your project folder is at the same level as the ninepatch folder (as in the download from github), you'll also want to set the Header Search Paths on your target to ../NinePatch//**, varying accordingly if you've moved any folders around.
Other than that the only thing I can see is that you will, of course, need to include the headers with #import <TUNinePatch.h>
NinePatchDemo built fine for me, so I can verify that their source does work.