Loading CustomView From nib file - iphone

I have a code that load the custom view from a nib file but there is a problem with the variable of that custom view.
- (id)initWithFrame:(CGRect)frame
{ self = [super initWithFrame:frame];
if (self) {
// Initialization code
HomeMainView* views = (HomeMainView*)[[[NSBundle mainBundle] loadNibNamed:#"HomeMainView" owner:self options:nil] objectAtIndex:0];
[self release];
NSArray* permission = [NSArray arrayWithObjects:#"user_photos",#"publish_stream", nil];
FBLoginView* fbLogin = [[[FBLoginView alloc] initWithPublishPermissions:permission defaultAudience:FBSessionDefaultAudienceFriends] autorelease];
[views.FBLogin addSubview:fbLogin];
[views.homeButton setTitle:#"asdf" forState:UIControlStateNormal];
self = views;
}
return self;
}
I am trying to add the fbLogin to the views object generated by the Nib file. The problem is the views.FBLogin generate the errors saying unrecognized selectors.
Does anyone know what is wrong here?

I had the same problem but it was because I needed to add this to my app delegate didFinishLaunchingWithOptions :
[FBLoginView class]
Without this the UIView was a UIView not an FBLoginView, hence the unrecognized selector.

Make sure that you have set the custom class in interface builder for the view. Select the view and press cmd+option+3 and set the custom class.

Related

iOS strange delegate behavior?

I have a really strange delegate behavior in iOS. I'm setting a custom delegate in a subclassed UIViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:nil bundle:nil];
self.baseNavigationBar.delegate = self;
self.baseNavigationBar.navigationController = self.navigationController;
[self.navigationController.navigationBar addSubview:self.baseNavigationBar];
}
The initWithNibName can use nil, when using the default nib, because internally it will check fora nil in the nibName.
if (!nibNameOrNil) {
nibNameOrNil = NSStringFromClass([self class]);
}
The delegate declaration from the baseNavigationBar object looks the following:
#property (nonatomic, retain) id<BaseNavigationBarDelegate> delegate;
/*same thing with assign, which I you should use*/
/*and in the .m of course #synthesize*/
And now 2 screenshots from the running application.
The first one show's the debugger values from the BaseListViewController, which is a subclass of BaseCoreViewController, which is a subclass of UIViewController.
The screenshot is taken, when the viewDidLoad method is called.
The second one show's the values from the BaseNavigationBar, which is a UIView subclass.
The screenshot is taken at a time, when the user clicks the "next" button
- (IBAction)nextAction:(id)sender {
if (self.delegate) {
[self.delegate navigationBarDidClickNextButton:self];
}
}
So why is this a problem? By clicking a button in the BaseNavigationBar my delegate is always nil, so the program is stuck. But when looking at the values from the BaseCoreViewController at the same time the delegate is not nil. Very strange.
Edit
The BaseNavigationBar is loaded from a nib file using the UINib loadNibNamed:owner:options: function.
Edit 2
So that's pretty much all of the code.
Edit 3
Finally we got the source of the error in the last pieces of the code... setting self = something totally not allowed...
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (!nibNameOrNil) {
nibNameOrNil = NSStringFromClass([self class]);
}
if (!nibBundleOrNil) {
nibBundleOrNil = [NSBundle mainBundle];
}
NSArray *topLevelObjects = [nibBundleOrNil loadNibNamed:nibNameOrNil owner:self options:nil];
/*Here is the bad part*/
self = [topLevelObjects objectAtIndex:0];
state = BaseNavigationBarButtonStateNext;
if (self) {
self.title = #"";
}
return self;
}
Solved using a Class method instead of defining a custom init.
If you are using nib file, you should declare the nib class while initialising your class object.
You have initialised initWithNibName:nil
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:nil bundle:nil];
but it should be like initWithNibName:#"BaseNavigationBar"
self.baseNavigationBar = [[BaseNavigationBar alloc] initWithNibName:#"BaseNavigationBar" bundle:nil];
Not sure what the problem is. Require some more code to analyze the problem. But what I can see is address of BaseNavigationBar in both the screen shots is different. It means the BaseNavigationBar object present in the controller is not the one which got the nextAction event as in second screen shot.

How to show a UIView inside a UIViewController in ios5?

I have a UIView designed in XIB file. Basically with a navigation bar and a button to close the UIVIew. I want to show this UIView in several UIViewControllers across the app.
Below is the code I have imp[emnted so far.However the UIView doesn't show up.
My ViewControllers are designed in storyboard however I needed a simple UIView that is why I created a new custom subclass of UIView alongwith a xib file of the same name.The File's Owner is also set to custom subclass. What else is required here?
#interface BottomSlidingView : UIView //this is my UIView
{
}
#implementation BottomSlidingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self setUserInteractionEnabled:YES];
NSLog(#"Bottom View Loaded"); //I get this log entry but the view doesn't showup.
}
return self;
}
- (BOOL)loadMyNibFile {
if (![[NSBundle mainBundle] loadNibNamed:#"BottomSlidingView" owner:self options:nil]) {
return NO;
}
return YES;
}
And this is how I call the custom UIView in my UIViewController.
-(void)shareButton:(UIBarButtonItem *)button
{
NSLog(#"share button clicked");
BottomSlidingView *bsv = [[BottomSlidingView alloc] initWithFrame:CGRectMake(20, 480, 280, 420)];
[bsv loadMyNibFile];
[self.view insertSubview:bsv belowSubview:self.optionsToolBar]; //this toolbar is a subview that I am adding to this view controller.
}
I see a couple problems with your approach:
Create the view instance from a nib file, rather than instantiating it with initWithFrame:. For example (if the custom view is the only root-level object in the nib file):
+ (instancetype)bottomSlidingView
{
return [[[UINib nibWithNibName:#"BottomSlidingView" bundle:nil] instantiateWithOwner:nil options:nil] lastObject];
}
Implement awakeFromNib or initWithCoder: instead of initWithFrame: (which isn't called when loading from nibs) in your UIView subclass.
In your view controller, you would use something like the following to create the view:
- (void)shareButtonPressed:(id)sender
{
BottomSlidingView *slidingView = [BottomSlidingView bottomSlidingView];
[slidingView setFrame:CGRectMake(20, 480, 280, 420)];
[[self view] insertSubview:slidingView belowSubview:[self optionsToolBar]];
}
Hope that helps.
Where ever you want to reuse a UIView of a UIViewController in another view controller you need to use this....
YourViewController * child = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];//View controller of view , you want to reuse
[self.view addSubView:child.YourView]; //YourView = Name of view, you want to reuse
[self addChildViewController:child];
[child release];
After adding childViewController All IBActions will be work in child.
And after removing this view You have to remove YourViewController from parentViewController other wise there will be memory issues.......

issue with xib loaded in a Grect

learning much from you guys, and after a few hours I finally managed to load a xib into a GRect for a search xib that I built.
Basically, when you tap a cell in main.xib, it loads search.xib in a Grect so that I can filter down a list, click o nthe value, and place back into the cell in main.xib.
However I still have the cells from main.xib that overlay (tvcells) that overlay my search.xib.
Also it seems that none of the code is initializing for search.xib, I put an NSlog message in viewdidload in the search.xib, and nothing shows up in the console, letting me know that none of that code was executed.
Any idea why?
Thanks!
CGRect container = [[UIScreen mainScreen]bounds];
container.origin.x = 0;
container.origin.y = 0;
NSArray *views = [[NSBundle mainBundle] loadNibNamed: #"ingredientSearchViewController" owner: self options: nil];
UIView *referencedView = (UIView *)[views objectAtIndex:0];
referencedView.frame = container;
[self.subView addSubview:referencedView];
NSLog(#"loaded subview but obviously not in subview xib");
Additional code that attempts to do this as a controller
if (self != nil){
[self.view removeFromSuperview];
}
if(self == nil){
ingredientSearchViewController *vc = [[[ingredientSearchViewController alloc]initWithNibName:#"ingredientSearchViewController" bundle:nil] autorelease];
vc.view.frame = [UIScreen mainScreen].applicationFrame;
vc.delegate = self;
[self.subView addSubview:vc.view];
}
viewDidLoad is a method in NSViewController.
And you are creating a View from Nib, therefore you should use the equivalent method awakeFromNib for NSView.

injecting UINibExternalObjects to an self initialzied ViewController

I want to navigate from one ViewController to another. As part of this I want to
pass the ViewController I want to navigate to some information. I encapsulated the
information into an Object that I want to hook up as an external object with the target
viewController.
I created the external Object inside IB gave it the identifier I referenced in the NSDictionary that is passed to the NibLoading method.
NSArray* topLevelObjs = nil;
NSMutableDictionary* options = [[NSMutableDictionary alloc] initWithCapacity:1];
NSMutableDictionary* config = [[NSMutableDictionary alloc] initWithCapacity:1];
id detailImageVC = [[SelectedImageModalViewController alloc] init];
SelectedImageModalModel* selectImageModalModel = [[SelectedImageModalModel alloc] init];
selectImageModalModel.imageName = #"img#2x.png";
[config setValue:selectImageModalModel forKey:#"SelectImageModalModel"];
[options setValue:config forKey:UINibExternalObjects];
topLevelObjs = [[NSBundle mainBundle] loadNibNamed:#"SelectedImageModalViewController" owner:detailImageVC options:options];
if ([topLevelObjs count] == 0)
{
NSLog(#"Warning! Could not substitute proxy objects in xib file.\n");
return;
}
[appDelegate.navigationController presentModalViewController:detailImageVC animated:YES];
[options release];
[config release];
[selectImageModalModel release];
[detailImageVC release];
What I expected was, that after I called presentModalViewController:animated: I would receive a call to viewDidLoad on the very same detailImageVC with my external objects
connected.
Instead neither happens. viewWillApear: will get called, but the detailImageVC won't hold my external reference.
Any idea, hind or comment is appreciated. Thanks!
viewDidLoad will be called if only ViewController loaded the view itself.
For example; initWithNibName does not load the view, it just sets the nib name. When ViewController needs its view in some future point and if there is no view in ViewController.view then ViewController will load view like you did AND THEN INVOKE viewDidLoad itself.
Your code loads the view of ViewController itself. So you should call the viewDidLoad method in your code like this:
topLevelObjs = [[NSBundle mainBundle] loadNibNamed:#"SelectedImageModalViewController" owner:detailImageVC options:options];
if (topLevelObjs.count == 0) {
NSLog(#"Warning! Could not substitute proxy objects in xib file.\n");
return;
} else {
[detailImageVC viewDidLoad];
}
If your detailImageVC does not hold your external object then you should check your nib file for IBOutlet bindings and your SelectedImageModalViewController for corresponding #property. If property is not strong like #property(nonatomic, strong) on ARC, or, is not reatin on Non-ARC like #property(nonatomic, retain) then it will not hold your object after awaking from nib.

iPhone: [subview release] removes my subview from the display

I have these two pieces of code. The first one works perfectly:
UIView *tmp = [[UIView alloc] initWithFrame:CGRectMake(0.0f, 60.0f, 296.0f, 44.0f)];
[self.dynamicView addSubview:tmp];
[tmp release];
The second one is pretty much the same, but the view doesn't show up.
CommentBox *commentBox = [[CommentBox alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 296.0f, 44.0f)];
[self.dynamicView addSubview:commentBox];
[commentBox release]; // Why does this remove the view?
If I remove the [commentBox release] the view surprisingly appears. But I don't see a different between these two code snippets.
The init for the CommentBox looks like this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Load the nib:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
self = [nibObjects objectAtIndex:0];
}
return self;
}
After thinking about Graham's answer I came up with the following solution:
I drag a new UIView (-> lets call it sub UIView) in Interface Builder in my main UIView
I give this sub UIView the correct size (because I cannot resize the main UIView, which is always 320x460)
I drag all my other elements in this sub UIView (so that all elements are attached to my sub UIView)
I give my sub UIView a tag number (Interface Builder -> View Attributes), e.g. "300"
In the code I do now the following within my -initWithFrame:
NSArray *nibObjects = [[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
UIView *subView = [[nibObjects objectAtIndex:0] viewWithTag:300];
[self addSubview:subView];
Hope that helps.
Update:
I just had another idea of doing it. Instead of the tag numbers you can also create a IBOutlet UIView *viewHolder in the CommentBox class and set the outlet in IB. Then in the initWithFrame: I do the following:
[[NSBundle mainBundle] loadNibNamed:#"CommentBox" owner:self options:nil];
[self addSubview:self.viewHolder];
You're doing weird things in -initWithFrame:. I'm not 100% sure that it's causing the problem you report, but I'm pretty sure it's:
wrong; and
causing a memory leak.
I don't think replacing a view object with something dearchived from a nib in its -init… methods is a good idea. Either load the nib from a controller class, or have your initialiser load the object's subviews from the nib without replacing self.