How to reload an object connected in xib - objective-c

I have a UIViewController (myViewController) with a XIB file. In this XIB file, I have connected an other object UIPickerViewController (myPicker).
When my UIViewController is allocated, initialized and pushed as a viewcontroller, the UIPIckerViewController displays its instance as it should.
The user can modaly open a settingscontroller from myViewController to adjust some settings.
When the settingscontroller is dismissed, myViewController is updated (buttons, text, tableview, etc).
However, myPicker is not Only when the UIViewController is initalized and pushed again, myPicker is updated.
Is there any good ways to reload myPicker in myViewController without initializing UIViewController again?

Try call [myPicker reloadAllComponents]; in viewWillAppear (for that you should make subclass of UIViewController).

Related

Custom view created with Interface Builder does not render when called in other views

I have an xib for the main window, and I created a custom view in the following steps:
Create a new class which inherits from NSView.
MyView.h:
#import <Cocoa/Cocoa.h>
IB_DESIGNABLE
#interface MyView : NSTableCellView
#end
MyView.m:
#import "MyView.h"
#implementation MyView
- (void)awakeFromNib {
NSLog(#"Post view awaking from nib.");
}
#end
Create a new xib, and set the root view's class to the class created above. And design in that xib.
Set outlets from the xib to the class.
And I tried to use this custom view in the main window in the following steps:
Drag a custom view to the main window's xib.
Set the class of that custom view to the class created above.
But nothing renders. From the log, I can see that code in awakeFromNib from the custom view class is executed. When I set the class to be IB_DESIGNABLE, the view gets empty in the main window's xib, different from what I designed.
I tried to set the file owner of the custom view's xib to the custom class, but nothing changed.
I guess the problem is that, the custom view's xib file is not actually loaded. When I googled it, there seem to be few references on this exact topic. So, how should I actually achieve this goal? I.e., design a view in IB, implement its methods in a class, associate these two, and expose it just like a system view for use in other xibs?
UPDATE:
I found a tutorial and realized what I lack (for correctly rendering the view when built). I have to add an outlet from the view in the xib to the view class:
#property (nonatomic, strong) IBOutlet NSView *view;
, and then load it in the (id)initWithCoder:(NSCoder *)coder method.
[[NSBundle mainBundle] loadNibNamed:#"MyView" owner:self topLevelObjects:nil];
[self addSubview:self.view];
But the view still won't render in the interface builder.
Your guess is correct: the xib is not being loaded. The nib loader doesn't know about your custom view's nib. The nib framework doesn't provide a facility for defining that connection, so you need to write code to load the xib.
Here's what I'd do. Add a contentView property to your custom view:
#interface MyView ()
#property (nonatomic, strong, readwrite) IBOutlet NSView *contentView;
#end
In your custom view's nib, set the custom class of the root view back to NSView and disconnect all the (no-longer-valid) outlet connections from it. Set the custom class of File's Owner to your custom class name (e.g. MyView). Connect the root view to File's Owner's contentView outlet, and connect all the other outlets from File's Owner to the appropriate objects in the nib.
Then implement awakeFromNib in your custom view subclass to load the nib and add the content view as a subview:
#implementation MyView {
BOOL hasLoadedOwnNib: 1;
}
- (void)awakeFromNib {
[super awakeFromNib];
[self loadOwnNibIfNeeded];
}
- (void)loadOwnNibIfNeeded {
if (hasLoadedOwnNib) {
return;
}
hasLoadedOwnNib = YES;
[[NSBundle bundleForClass:self.class] loadNibNamed:NSStringFromClass(self.class) owner:self topLevelObjects:nil];
self.contentView.frame = self.bounds;
self.contentView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[self addSubview:self.contentView];
}
#end
Note that you have to be careful not to allow infinite recursion. When your app loads the main window's nib, it will create an instance of MyView and (eventually) send it awakeFromNib. Then, in awakeFromNib, MyView loads its own nib, where it is the File's Owner. The nib loader sends awakeFromNib to File's Owner, and this will happen while you're already in -[MyView awakeFromNib]. If you don't check for this, you get a stack overflow due to unbounded recursion.
You aren't providing any code, but here are some sanity checks:
Are you specifying the nib name correctly? In iOS its caps sensitive, but I don't think it is for you.
Check the package, is the nib actually there? Make sure it is part of the target you are building.
Could also be a frame issue. Make sure your auto-resizing parameters are set up correctly and that everything is in frame.
Another check you can do is set your IBOutlets to the actual frame of a UIView (or other) that you are interested in. Then in awakeFromNib, you can make sure their frame exists, or that they exist at all.

UIViewController with many xibs

i am developing an iOS application. I have a controller : iPhonePopUpController, in this controller i have a xib like this image :
My question is, can i add an other xib to this Controller and loaded it when i need it or should i create a second controller to load my second xib ?
You can load anything from a XIB using:
[[NSBundle mainBundle] loadNibNamed:#"YourOtherXIB.xib" owner:someObjectThatWillTakeThePlaceOfFilesOwner options:0]
This line unarchive the XIB named YourOtherXIB.xib by creating the instances of the objects you have in your XIB, and then connect all the outlets and actions you defined in the XIB, and return the list of top-level objects.
When you create a XIB whose File's Owner is an UIViewController, typically you then initialize your UIViewController using code like this:
UIViewController* vc = [[[UIViewController alloc] initWithNibName:nibName bundle:bundle] autorelease];
What this code basically do internally is that it stores the nibName and bundle you provide in some internal property, and when it needs to load its view (especially the first time it needs to display it onscreen), it loads the view from the XIB using something like the line quoted above:
[bundle loadNibNamed:nibName owner:self options:0];
As you connected the view in your XIB to the view IBOutlet of the File's Owner's (which in that case is the self passed as an argument, namely the UIViewController itself), then the view property of your UIViewController will be populated with the view that has just been unarchived from the XIB. And that's how UIViewController loads its view from a XIB file.
But of course you can do the same for your own classes and do not need your File's Owner to be an UIViewController. Simply make your File's Owner be whatever class fits your need, expose a custom IBOutlet from this class and connect it to your objects in your XIB.
For example you can have a MyCustomClass class that declares an IBOutlet UIView* myOtherView;. Define the class of your File's Owner in your XIB to be of the class MyCustomClass, then bind the myOtherView outlet to the view to load from your XIB. Then in the code, create an instance of MyCustomClass and use the above loadNibNamed:owner:options: method by passing this MyCustomClass instance as the owner parameter
Or you can reuse your UIViewController that loaded your primary XIB to load your other view from your secondary XIB too: simply add an IBOutlet UIView* otherView in your UIViewController subclass. In your first XIB, you will connect the view IBOutlet to your primary view but keep the otherView IBOutlet unconnected. In your second XIB, you will connect the otherView IBOutlet to your other view but keep view IBOutlet unconnected. When loading your UIViewController with the first XIB, the view property will be set to the view loaded from your XIB. Then if you want to lazy-load the otherView from the other XIB at a later time, simply call loadNibNamed:owner:options with OtherXIB.xib as the nib name and self as the owner. The OtherXIB will be unarchived and otherView property will be filled with that loaded view.

ViewControllers Navigation

I have one base view controller "contentViewController" with one button
the action on button is
(IBAction) goBack:(id)sender
.h file
#interface ContentView : UIViewController {
}
#property(nonatomic,retain) UIViewController *display;
-(IBAction) goBack:(id) sender;
.m file
#synthesize display;
-(IBAction) goBack:(id)sender{
UIViewController *view= display;
[display release];
[self presentModalViewController:view animated:YES];
}
and there are some other view controllers already exist each view controller contain on button to show content on the contentViewController.. here is one class example:
.h file
#interface Info : UIViewController {
}
-(IBAction) viewHealthInfoContent:(id) sender;
.m file
-(IBAction) viewHealthInfoContent:(id)sender{
ContentView *cv=[ContentView alloc];
[cv setDisplay:self];
[self presentModalViewController:cv animated:YES];
[cv release];
}
the case is, each time i show content from one view controller i need to go back to it. using that one goBack button on the contentViewController but when i click the go back button it doesn't do any think !!! any help
When you want to go back your previous viewController, use dismissModalViewControllerAnimated:: method.
According source :
Dismisses the modal view controller that was presented by the receiver.
In iOS, you can display views modally by presenting the controller for the modal view from your current view controller. When you present a view modally using the presentModalViewController:animated: method, the view controller animates the appearance of the view using the technique you specify. (You can specify the desired technique by setting the modalTransitionStyle property.) At the same time, the method creates a parent-child relationship between the current view controller and the modal view controller.
Source

Cocoa - Link IBOutlet to Separate Nib

I have a nib file in which I load at a certain point in my application. Would it be legal for me to link a NSWindow IBOutlet from my AppDelegate to the 2nd nib file's window? In other words, my IBOutlet is not being connected to the MainMenu xib file that Xcode creates on default. If this was legal, can I have access to the NSWindow's frame and other features?
Yes you can do that. In your second nib file, I would use a NSWindowController as the file's owner to the nib. Then in your AppDelegate, create an instance of the NSWindowController and then load the nib. From there, you can inspect the properties of the window owned by NSWindowController or do whatever you want with the window.
Here is an example
#interface MyAppDelegate : NSObject
{
NSWindowController *myWindowController;
}
#end
#implementation MyAppDelegate
- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
myWindowController = [[NSWindowController alloc] initWithWindowNibName:#"MySecondWindow"];
[[myWindowController window] center];
[[myWindowController window] makeKeyAndOrderFront:self];
}
#end
In your second nib, set the File's Owner to be your app delegate class. Then attach the outlets as needed within IB. At run time, call [NSBundle loadNibNamed:owner:] and be sure to pass self as the owner.
Yes, this would be legal as long as the App Delegate is the File's Owner of the nib you are loading. That said, if you unload the nib later, you have to make sure that all top level objects in the nib are properly released (otherwise you'll create a memory leak).

Loading custom UIView in UIViewController's main view

I have subclassed UIView and created a NIB that controls the main logic for my application.
Hoping the view will scale nicely, I want to use it for both the iPhone and iPad versions of the app.
On the iPhone the view will cover the full screen. On the iPad the view will cover only part of the screen.
I have read that you shouldn't use UIViewControllers to control only part of the screen. So, I am trying to embed the custom UIView in the main UIViewController's view using IB.
How can this be done?
After a lot of trial and error I found a solution based on an approach explained in the following question, answered by Brian Webster.
The solution was originally suggested for a Cocoa environment. I hope it is valid in an iOS environment as well.
Create the main view controller with a NIB-file. In the NIB, the File's Owner should correspond to the class of your main view controller.
Create a custom view controller with a NIB-file. In this NIB, the File's Owner should correspond to the class of your custom view controller.
Create a custom view controller property in your main view controller class.
Create an UIView property in the main view controller class. It will hold your custom view controller's view. Define it as an IBOutlet, so it can be linked in the NIB.
Drop a UIView in your main view controller's NIB. Link it to the main view controller's view IBOutlet. It will be used as a placeholder for the custom view.
In the main view controller's viewDidLoad method, load the custom view controllers NIB, determine the custom view's frame size and copy the view in the main view controller's view.
Here is some code:
MainViewController.h
#interface MainViewController : UIViewController {
CustomViewController *customViewController;
UIView *customView;
}
#property (nonatomic, retain) CustomViewController *customViewController;
#property (nonatomic, retain) IBOutlet UIView *customView;
#end
MainViewController.m
- (void)viewDidLoad {
CustomViewController *controller = [[CustomViewController alloc] initWithNibName:#"CustomViewController" bundle:nil];
self.customViewController = controller;
[controller release];
customViewController.view.frame = customView.frame;
customViewController.view.autoresizingMask = customView.autoresizingMask;
[customView removeFromSuperview];
[self.view addSubview:customViewController.view];
self.customView = customViewController.view;
[super viewDidLoad];
}
Add an IBOutlet propertyfor your custom UIView to the UIViewController, and additional outlets for any subviews you wish to access.
Go to Interface Builder, select the "File's Owner" object in your NIB and in the Inspector go the rightmost tab set its class to match your UIViewController's class.
Connect the IBOutlet from step one on the "File's Owner" to your custom UIView.
In XCode, when you need to load your view, do something like this:
--
[[NSBundle mainBundle] loadNibNamed:#"MyNib" owner:self options:0];
self.myCustomView.frame=self.view.bounds; // make view fill screen - customize as necessary
[self.view addSubview:self.myCustomView];
When you load the NIB, the outlet(s) you set up in step 1 will be populated with the objects loaded from your NIB.