iphone dev: UIImageview subclass interface builder - how to call custom initializer - iphone

I messing with iphone developement. I have a uiimageview subclass that I want to use to detect touches. I have sucessfully added to interfacebuilder and I can detect a touch in my UIImageview subclass within my application so all is good on that front. however my UIImageView subclass has a custom initializer which is not called when it is created in interface builder.
if I manually initialize the UIImageview and add it programmatically I think it will work but then I lose the ability to 'see' my positioning in Interface builder.
how can I either
1) 'see' a uiimageview in interface builder that is added in code? (not possible?)
2) call my custom initializer when the subclass is instantiated in interfacebuilder.
thanks
Hi thanks for suggestions. I think I'm getting closer to understanding the relationship between the xib and the viewcontroller.
I now am sucessfully adding my UIImageView subclass programmatically and using my custom initiializer which overrides InitWithFrame.
I think I read that the xib calls 'awakeFromNib' so I could equally add my iniitialization code in there. I like the idea of adding it programmatically as I have more control (although harderto set up my IU)
so one more realted question. if I add an UIImageView subclass in interface builder. I can see it and detect touches on it. if I want to refer to it in the view controller class do I have a pointer to it? i.e. is there a variable name for it? the UIImageViews I create myself I obviuosly know what they are called.....

You likely have put your instructions in the wrong initializer.
According to the documentation, objects unarchived from a NIB are initialized with initWithCode: if they conform to the NSCoding protocol; objects that don't conform to NSCoding are initialized with init.
In this particular case, UIImageView does conform to NSCoding. It's likely that you have you intended for initWithFrame: to be called and put your instructions in that method.

Can you not simply put your initialisation logic in viewDidLoad? In particular,
-(void)viewDidLoad {
[super viewDidLoad];
// Put whatever was in your custom initialiser here.
}

Related

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.

How to add a subclass of UIView to a UIScrollView?

I have a class that subclasses UIView called DrawView. This class contains custom drawing in the drawRect: method. I want to add this to a UIScrollView programmatically in a UIViewController class controlling the view which the UIScrollView has been added to. Also, I want the instance of DrawView to be a global variable.
I kind of confused and I am not really sure of anything, except that at some point I will have to call [scroller addSubview:drawViewInstance];. Thanks
Yes what you have written is correct. Also your subview should be a new class overriding the methods you need. You can maintain it globally by providing a method to return the instance more like a singleton.
Put the variable into the app delegate class. Alloc and init it and you can access it using the getter. Declare the variable in your delegate.
[UIApplication sharedApplication].delegate].globalInstance;

IBOutlet UIView loaded from a Nib file

I am loading a UIView from a NIB file with outlets and I want to change the properties of these outlets. I am wondering when I should do that because in the init method the outlets are nil and that make sense and in the drawRect method I can change the properties of my outlets but I'm not sure it's the proper way to do that.
Is there a method called after the init method and the drawRect method where I could do what I want ?
Thank you.
There's layoutSubviews - this will definitely be called before the first call to drawRect?
The UIViewController method viewDidLoad is called after a nib has been loaded and after loadView is called. (loadView allows you to load a view programmatically instead of using a nib. However, nibs are much better so it's best to pretend that loadView doesn't exist.)
NSObject implements awakeFromNib. awakeFromNib is called after an object has been loaded from a nib. Here's a quote from the docs:
Typically, you implement awakeFromNib for objects that require additional set up that cannot be done at design time. For example, you might use this method to customize the default configuration of any controls to match user preferences or the values in other controls. You might also use it to restore individual controls to some previous state of your application.
drawRect: is a UIView method, only use it if you need to do Quartz drawing. Using layers and Core Animation is more efficient. If you want to configure a custom UIView (i.e. you've subclassed UIView instead of configuring a view within a UIViewController) then you should use initWithCoder:.
If you want to use IBOutlets in your initialization code for a UIView - override awakeFromNib. This is the first method called after outlets have been configured.
With regard to UIViewController - viewDidLoad and viewDidAppear are often convenient locations to put your initialization code in but beware: autolayout has not happened at this stage which means strange autoresizing effects can cause you bother. The better solution is to put your code in viewDidLayoutSubviews which is the first lifecycle method called after autolayout.

Call a function in a UIViewController's UIView

I've created a view controller and the associated view using the interface builder. I'm trying to call a function that I added to the UIView from the UIViewController. I'm not sure how to call that function though.
I've tried
[self.view myFunction]
but that just makes my program crash.
Did you declare your IB outlets and connect the method to it?
Your view (more accurately nib)'s file owner should be set to your viewController class.
Unless your calling drawing functions and methods you shouldn't call anything on the view. You just don't need to.
Edit: grammar corrections.
How is the view getting initialized? Is it a custom view type? If your view is being initialized from a nib, make sure that the class on the view type is the class that has the method implemented.
It is probably crashing because UIView does not have a method named myFunction. In order to add myFunction to a UIView object, you need to subclass it.
I assume you have subclassed your UIView, and called it something like MyView. You also probably have subclassed your UIViewController and called it MyUIViewController. Therefore you may have:
#interface MyViewController : UIViewController {
MyView *myView;
....
}
Now you can call [self.myView myFunction];
That's one way. Another way may be:
[(MyView *)self.view myFunction];
This depends on whether myView is the first view in the hierarchy (or should be set up in your NIB files).

Arbitrary objects to handle actions?

My question may be a bit stupid, but why can't any object instantiated in IB handle, say, button click? I mean I'm able to add my own object to a xib, and link outlets to cotrols and control actions to object's method, but once I press the button everything just crashes (uknown selector).
Do you guys have a hint around that?
EDIT: The code, as requested:
#interface TextController {
IBOutlet UILabel * textLabel;
IBOutlet UITextField * textField;
}
-(IBAction)buttonClicked:(id)sender;
#end
#implementation TextController
-(IBAction)buttonClicked:(id)sender {
textLabel.text = #"Ololo";
}
#end
Connections in IB are ok, just believe me. It's really hard to get them wrong with all this drag'n'drop stuff :)
EDIT 2: TextController is not a file owner (in this case it works fine). However, I just want to understand why I can't wire up an action to some object (may be even not a subclass of UIViewController).
You can wire outlets and actions to any object in the nib-file. Drag an NSObject form the library palette onto your nib-file, in Interface Builder. Then go to the Identity tab of the information palette and set the Class of your object.
This way you can instantiate any object of any class from your nib. If the target you want to hook to is statically created from the nib-file. Make sure that the file's owner have at least one reference to your object, or else it will be deallocated as soon as it has been created. Targets are not retained by the sender.
If the object you want to hook up should not be statically created from your nib, then implement awakeFromNib in a class that is instantiated from the nib-file and hook up the targets in code.
Last option is if you do not have any sub-class of your own in the nib-file at all. Then implement initWithNibName:bundle: in your UIViewController subclass, and hook up your targets in code after calling the super implementation.
post code, this usually means you dont have your connections wired up correctly. Is file's owner TextController in IB?