Why not UIImage itself but UIImage view - iphone

I'm learning to develop apps for Iphone. I follow a book by Apress which I find very useful. But as nothing is perfect some issues are not well described and just skipped.In one of the applications I have to assign five images to each of the five components of a pickerview. But my question is why do/can not we use an instance of UImage itself but UIImageView to display on the picker.

As in above question you are asking why we can not use UIImage instead of UIImageView as component for UIPickerView.
UIImage is subclass of NSObject class, If we talk in terms of M-V-C its a M(model). and model in itself is nothing until its used.
UIImageView on the other hand is subclass of UIView which stands for V(view) in M-V-C so it uses your model for its contents.
So, they are two different things, not alternate. Also, if you go through UIPickerView's class documentation then you will find that it has method
- (UIView *)viewForRow:(NSInteger)row forComponent:(NSInteger)component
that configures view for specified row component. so it meanse we need view(UIImageView) and not the model class(UIImage). here for component you can return subclass of UIView.
Please refer apple's documentation.
Thanks,

You need a frame to place your photo, similarly You need UIImageView as place holder to place UIImage.

UIImage is just an Image loaded from file. View is able to handle touch events and only Views are displayed.

Related

Best way to include UIImage in custom UITableViewCell?

I want to know what is the best and most optimized way to draw UIImage in a custom UITableViewCell that has many elements in it (several images, 2 labels, gradient background). I read that drawRect is the recommended way to go with this since there are several subviews involved and its better to have them all composed as one view content using drawRect. But at the same time I read somewhere else that UIImageView is the preferred way to optimally handle images (caching, fast rendering, etc). I'd appreciate some enlightenment.
Thanks
AF
I would recommend UIImageView for its easiness of use. You can drag & drop it in the Interface Builder or just add it programmatically.
I went to an iPhone Tech Talk once, and a performance engineer said if you're using a UIImage in a UITableView you should add it with the class method [UIImage imageNamed:] to get the most efficient use of the class. Of course you would need to embed that in a UIImageView. I usually find any time there are class methods available to make something for you, Apple is very efficient at the way they do it.
I would suggest you to use
cell.imgView.image = [UIImage imageNamed:#"123.jpg"];

How does UIImage get constructed when created from an XIB?

I'm trying to do some fanciness with XIBs and that includes wanting to somehow get and store the paths of images loaded from the xib. To do this, I made some categories and did some method swizzling to override all the UIImage constructors to save their path before calling their parent constructor.
But due to Apple's black box BS with all their XIB stuff, absolutely none of the exposed constructors for UIImage seem to get called when I create a UIImageView through [UIViewController initWithNib...].
Does anybody know what function call happens or how they do this? I can't find any information whatsoever that exposes what initWithNib actually does behind the scenes.
Thanks!
EDIT:
If you're in a similar situation, you may try using the accessibilityLabel / accessibilityHint which is automatically populated with the image path. The only issue is that accessibility needs to be enabled or these values are nil.
I know the objects constructed from a Nib are being unarchived according to the NSCoding protocol; you need to override initWithCoder: in this case.
You could use swizzling to replace UIImageView's initWithCoder: method, then snoop around to see if an image name or path is available in any of the coder's keys. This might be more effective than hacking UIImage itself, since for all we know UIImageView could be using a custom subclass that you don't have access to.
the initWith... methods are meant for programatically creating UIImageView objects.
Sounds like you want to catch things as they are instantiated from XIB files. That would be the parent class UIView's [initWithCoder:] method.
As the UIView documentation says:
initWithCoder: - Implement this method if you load your view from an
Interface Builder nib file and your view requires custom
initialization.
You are both close to right - I tried doing this with UIImageView which works for initWithCoder as you guys are both suggesting. However, UIImage doesn't get initWithCoder called for some reason, instead it uses initWithCGImageStored:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation.
If and when I actually get the path out of this as I desire I'll post it up here. Thanks for the help, gents.

UIViewController encodeWithCoder fails when view contains a UIButton with custom image

Basically, my problem is exactly what it says in the title. When I try to encode a subclass of UIViewController, calling [super encodeWithCoder] gives an NSInvalidArgumentException. Specifically, I get -[UIImage encodeWithCoder:]: unrecognized selector sent to instance XxXXXXXX.
The only image image in the view is on a UIButton, which is also supposed to conform to NSCoding, and the stack trace includes a call to [UIBUtton encodeWithCoder]. The button is created programmatically with [UIButton buttonWithType:UIButtonTypeCustom], and the image is set with setImage: forState:. I really have no idea what is going on here. Am I missing something obvious, or does UIButton just not really conform to NSCoding?
I can't imagine why you would want to be archiving view objects within your app, but you probably need to add NSCoding support yourself by writing a category on UIImage.
For details see: iPhone - Why does the documentation say UIImageView is NSCoding compliant?
View objects support NSCoding because the view loading system uses it to load objects from Nib files. But the UINib class does some additional work that NSKeyedArchiver does not.
If you just want to store state between launches, it's better to store data and not view state. Especially if you ever plan to update your app and make any changes whatsoever to the view layout. (This is the motivation behind Model/View/Controller separation.)

Dynamically creating a uiImageView

I'm still very new to cocoa touch so please excuse any terminology that I may have got wrong.
I have a bunch of images in my bundle consecutively named image0.png, image1.png etc...
I have a picker in a viewcontroller and an instance variable that keeps track of the current row.
When a user clicks a button I want to be able to create a uiImageView object (and first test whether the view already exists) based on the row number, ie: uiImageView *imageView1 for row1.
Is this possible or would it just be easier to create a line of code for each possible case?
I hope this makes sense, and thanks in advance for anyone that can shed any light!
Why not just create one UIImageView in Interface Builder and then swap out the image it's displaying depending on your picker index?
Implement:
- (void)pickerView:(UIPickerView *)pickerView
didSelectRow:(NSInteger)row
inComponent:(NSInteger)component
{
[imageView setImage:[imagesArray objectAtIndex:row]];
}
Where imageView is an instance variable (IBOutlet) connected to the image view control in Interface Builder.
Ok, that makes sense.
I think what I was trying to do was take lazy loading to the extreme by only creating the uiImage object and the uiImageView object the first time it was called on from the picker (having clicked the "go" button).
I anticipate having around 40 images that will fill the screen.
Programatically, would this be an acceptable method for this number of images?
Thanks very for the responses guys.

Possible to copy CALayer from UIView?

Here's my setup: I have a CALAyer to which I want to add sublayers. I create these sublayers by setting upa UILabel and then adding the UILables layer to my main layer. Of course this leaves the heavy UILabel object hovering around in the background. Is it possible to get the layer with all its content from a UIView and get rid of the UIView itself?
I already tried this:
UILabel* label;
[...]
[mainLayer addSublayer:[label.layer copy]];
[label release];
But whenever I release the UIView, the content of the layer is also removed. Is this even possible or does the UIView's layer always need the UIView itself to show its content? I thought of the layer as a kind of canvas, to which the UIView paints. I guess I could be wrong with this assumption :)
I can't understand why you wouldn't be able to copy a layer. True a layer is an "integral part" of a UIView. But in the end it is just another object with several properties.
Actually there is a method for CALayer called:
- (id)initWithLayer:(id)layer
But it isn't intended to make a copy of a layer. (You can read Apple's docs for the reasoning why)
CALayer does not conform to NSCopying, so you have two options:
Subclass it and implement
"copyWithZone:" (and conform to
NSCopying)
Write a method/function that will
return a "copy" of a CALayer
Regardless of which way you choose, the question you have to ask is: Which properties of the CALlayer do you want to copy?
Let's say you want to copy just the contents and frame:
CALayer copyLayer = [CALayer layer];
copyLayer.contents = theLayerToBeCopied.contents;
copyLayer.frame = theLayerToBeCopied.frame;
return copyLayer;
You could go through and copy every property of the layer, or just copy the ones you need. Might be a good method to put in a CALayer category.
It is not possible: a layer is a property of a UIView. Therefore, when you release the UIView, its layer is gone. Your idea of thinking of the layer as a kind of canvas is not wrong. But, the layer is an integral part of its UIView.
UIViews are not that heavy in iOS. For the most part, you can think of them as a supporting wrapper around a CALayer. Unlike on Mac where a NSView doesn't have to be backed by a CALayer, that's not true in iOS. All UIView instances are CALayer-backed and that's where most of the heavy lifting is. Apple's docs even say things like 'Don't bother animating a UIView's layer. Animate the UIView directly as it's essentially just sending it all down to the layer anyway.' (Paraphrased, of course.)
Point being, unless you specifically need UILayer instances for something that's not directly supported by a UIView, just stick with working with UIViews entirely and you should be good to go.
UILabel really isn't a very complex control. I suggest you give up this line of attack and learn how to draw what you want using Quartz into a fresh CGImage. You can then assign this to the contents property of the CALayer without having to worry about all this other stuff.
You can also circumvent UILabel entirely and create your text with a CATextLayer.
use CAReplicatorLayer, you will be able to completely replicate that layer