UIView Buttons loaded with XIB do not work - iphone

I've loaded a UIView (FirstView.m) with a separate XIB (SecondView.xib), but the buttons in that XIB crash the app. The code for the buttons (IBOutlet & IBAction) are in SecondView.m.
Do I need to point the code from SecondView.m to FirstView.m? I tried using #import and #class... but was unsuccessful.
The code I'm using is completely valid... I'm pretty sure the issue has something to do with the XIB being loaded into the UIView... and then possibly losing its connection to the implementation file. Thoughts?
Thanks in advance!
FirstView.h
#import <UIKit/UIKit.h>
#interface FirstView : UIViewController {
IBOutlet UIView *SecondViewPopUP;
IBOutlet UIButton *openBTN;
}
#property (nonatomic, retain) UIView *SecondViewPopUP;
#property (nonatomic, retain) IBOutlet UIButton *openBTN;
-(IBAction)showPopUp:(id)sender;
FirstView.m
#synthesize SecondViewPopUP;
#synthesize openBTN
- (void)viewDidLoad {
SecondViewPopUP.alpha = 0;
// Add IncidentsViewController to view
SecondView *SecondV=[[SecondView alloc] init];
SecondV.view.frame = CGRectMake(0, 0, 262, 269);
SecondV.view.clipsToBounds = YES;
[SecondViewPopUP addSubview:SecondV.view];
SecondViewPopUP.frame = CGRectMake(0, 76, 262, 269);
[SecondV release];
}
-(IBAction)showPopUp:(id)sender {
NSLog(#"Stats Button was pressed");
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.4];
SecondViewPopUP.alpha = 1;
[UIView commitAnimations];
}
SecondView.h
#import <UIKit/UIKit.h>
#interface ShareViewController : UIViewController {
IBOutlet UIButton *share_facebook;
IBOutlet UIButton *share_twitter;
}
#property (nonatomic, retain) IBOutlet UIButton *share_facebook;
#property (nonatomic, retain) IBOutlet UIButton *share_twitter;
-(IBAction)shareOnFB:(id)sender;
-(IBAction)shareOnTwitter:(id)sender;
SecondView.m
#synthesize share_twitter, share_facebook;
- (void)viewDidLoad {
[super viewDidLoad];
}
-(IBAction)shareOnFB:(id)sender {
NSLog(#"Shared on FB");
}
-(IBAction)shareOnTwitter:(id)sender {
NSLog(#"Shared on Twitter");
}

First of all FirstView (and presumably SecondView) is a UIViewController not a UIView so naming it "FirstViewController" would be much clearer. Views and view controllers are very different things.
Secondly you are adding a UIViewController's view as a subview of another view on the line "[SecondViewPopUP addSubview:SecondV.view];" That's not how UIViewControllers are expected to be used and the UIViewController programming guide recommends against it for good reason.
Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy. In iPhone applications, the views in a view hierarchy traditionally cover the entire screen, but in iPad applications they may cover only a portion of the screen. The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
Finally if you were to post the error listed when your app crashes we would probably see that you are attempting to send -shareOnFB: or -shareOnTwitter: messages to an instance of "FirstView" which does not implement them because your nib bindings are not configured appropriately ie you set the File's Owner of the nib to be "SecondView" and then loaded it with an instance of "FirstView" as its owner. Impossible to say for sure without more data.

Related

How to add a popup UIView (of a customized class) on a UIViewController

I'm new on this, and I would like to get some advice because I don't know what I'm doing wrong.
I want to make an app in xcode, with a UIView with some items, and when you do something, another UIView (smaller than the first) pops up above the first UIView. The popup UIView would be a customized class.
I have started with the UIViewController template and the initial UIView, and I have linked all the items in the .storyboard, and it works. But when I create my own UIView class (from objective-C class), put the second UIView over the first in the storyboard and link it to my class, something goes wrong.
The UIView appears, but when I try to set it to hidden, it doesn't answer. It's like it's not receiving the messages, so I think I don't link it well programmatically and just appears because of the storyboard.
I don't know if I have to create another UIViewController instead of the UIView, or if this is the correct path.
Can anybody explain me a little, or just write a little code snippet with the instantiation of the second view and adding it?
Lots of thanks!!
(I paste some code, of the declaration in .h and instantiation in .m)
#import <UIKit/UIKit.h>
#import "EditView.h"
#interface ReleaseViewController : UIViewController <UIWebViewDelegate, UISearchBarDelegate> {
IBOutlet UIWebView *web;
IBOutlet UISearchBar *search;
IBOutlet EditView *evHack;
}
#property (nonatomic, retain) IBOutlet UIWebView *web;
#property (nonatomic, retain) IBOutlet UISearchBar *search;
#property (nonatomic, retain) IBOutlet EditView *evHack;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
search.delegate = self;
web.delegate = self;
evHack = [evHack initWithFrame:CGRectMake(0, 44, 320, 377)];
[evHack setHidden:YES];
}
EditView Class (I still have nothing):
#import <UIKit/UIKit.h>
#interface EditView : UIView
#end
#import "EditView.h"
#implementation EditView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSLog(#"View created");
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
initWithFrame only works when you alloc/init an app. If its already initialized, in this case by the storyboard, just set its frame:
evHack.frame = CGRectMake(0,44, 320, 377);
I don't know what it looks like in IB, But setting its frame in code may be redundant if you set it in IB too. To check whether evHack is hooked up right, NSLog evHack in viewDidLoad. If you get nil back, it's not hooked up right.

Subclassed? UITabBarController wont autorotate

Noobie so bear with me.
I've have been following the O'Rielyy Learning iPhone Programming and various threads on here to build my first iPhone App. So far so good, but the final stumbling block at the projects end is getting the App to autorotate (the beta using only uiwebviews was rejected for not auto-rotating)
I have the mail App delegate, which adds a UITabBarController
// myNewsUKDelegate.h
#interface myNewsUKDelegate : NSObject <UIApplicationDelegate, UITabBarControllerDelegate> {
UIWindow *window;
UITabBarController *tabBarController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;
#end
// myNewsUKDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Add the tab bar controller's view to the window and display.
[self.window addSubview:tabBarController.view];
[self.window makeKeyAndVisible];
return YES;
}
There is are .h and .m files for tabBarController - I added all the UINavigationControllers in IB, which in turn add a UITableView
See image at http://flatearth.co.uk/nib.png (too noob to post images in questions!)
From my reading I understand that the issue is the UITabBarController I added to the main view needs to be 'subclassed' and have this code added.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
The next view down/in/subclassed (whatever the correct terminology is), which has .h and .m files is the FirstViewController which adds the table view, this has shouldAutorotateToInterfaceOrientation already set.
#interface FirstViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
UITableView *tableView;
NSArray *userList;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#property (nonatomic, retain) NSArray *userList;
#end
#implementation FirstViewController
#synthesize tableView;
- (void)viewDidLoad {
[super viewDidLoad];
// I tried adding
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
// lots of other code ; )
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
So the problem appears to be that when [self.window addSubview:tabBarController.view]; adds the tab bar it doesn't add the shouldAutorotateToInterfaceOrientation returning YES bit.
It appears that I need to add a tabBarController subclass, with the shouldAutorotateToInterfaceOrientation in it. So I read up and tried this, as suggested on the interwebs...
// tabBarController.h
#import <UIKit/UIKit.h>
#interface tabBarController : UITabBarController {
}
#end
// tabBarController.m
#import "tabBarController.h"
#implementation tabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
#end
and adding
#import "tabBarController.h"
to myNewsUKDelegate.m
But that fails with "error: accessing unknown 'view' class method" at the
[self.window addSubview:tabBarController.view];
line in myNewsUKDelegate.m
Further searching hasn't produced anything helpful and my recent Xcode knowledge has now ran dry : ( Any help appreciated.
From my reading I understand that the issue is the UITabBarController I added to the main view needs to be 'subclassed' and have this code added.
No, you don't need to do that. The tab bar controller determines if it supports a specific interface orientation or not by asking all its child controllers if they support this orientation. In your case, these seem to be navigation controllers, which in turn ask their current child controller if it supports the orientation.
In other words, you have to make sure that all your custom view controllers return YES for the desired interface orientation.
You don't need a subclass, you need a Category on UITabBarController. Basically you create a file called UITabBarController + Autoresize.h (and .m)
In the .h:
#import <UIKit/UIKit.h>
#interface UITabBarController (Autoresize)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation;
#end
in the .m:
#import "UITabBarController + Autoresize.h"
#implementation UITabBarController (Autoresize)
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
//do custom checks here if you only want to autorotate it in certain views or whatever
}
#end
but as the other poster pointed out, ALL the parent views of the view you wish to rotate must support rotation.

One UIViewController with many UIViews

I'm creating an app with one UIViewController and many UIViews. I have MainViewController with a UIView underneath it that displays when loaded up and a few other UIViews all in the MainWindow.xib. How do I go about switching from one View to the next?
Update:
Thanks for the reply.
I have added MainViewController to my appDelegate.
On FinishedLaunching: [window addSubview:[viewController view]];
That View Controller has a function in it called goToNextPage.
-(IBAction)goToNextPage:(id)sender{
[self.view removeFromSuperview];
[self.view addSubview:tableOfContents];
}
In Interface Builder I have that View Controller added to MainWindow.xib. Under that View Controller I have a UIView (called Cover) that loads as it's child on startup and another UIView (eventually many) named TableOfContents that is on its own.
I tried to post an image of my MainWindow.xib here but apparently my Reputation isn't high enough.
The UIView Cover has a button on it that is linked to the goToNextPage function.
When I hit the button the page goes blank as if the one view is successfully being removed but the next is not being loaded.
How do I get the goToNextPage function to switch the preloaded UIView Cover with the other UIView called TableOfContents?
Another Edit:
BookTest6AppDelegate.h:
#import <UIKit/UIKit.h>
#class MainViewController;
#interface BookTest6AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
IBOutlet MainViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MainViewController *viewController;
#end
BookTest6AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[window addSubview:[viewController view]];
[window makeKeyAndVisible];
return YES;
}
MainViewController.h
#import <UIKit/UIKit.h>
#class TableOfContents;
#interface MainViewController : UIViewController {
IBOutlet TableOfContents *tableOfContents;
}
#property (nonatomic, retain) IBOutlet TableOfContents *tableOfContents;
-(IBAction)fGoToTableOfContentsController:(id)sender;
-(IBAction)fGoToNextPageController:(id)sender;
#end
MainViewController.m
#import "MainViewController.h"
#import "TableOfContents.h"
#implementation MainViewController
#synthesize tableOfContents;
-(IBAction)fGoToTableOfContentsController:(id)sender{
[self.view removeFromSuperview];
[self.view addSubview:self.tableOfContents];
}
-(IBAction)fGoToNextPageController:(id)sender{
}
My UIView Classes basically just initiate buttons that link to the functions defined in MainViewController.h.
First you need to know when switching from one to another.
Then you say it to your MainController and addSubView to the mainController.view an another view.
Maybe if you give us more informations or code we could help you a little more :-)
Good Luck
Vincent
Edit :
[self.view removeFromSuperview];
Here you are removing the window view. I think it's not the better way ^^ Try
[ viewController.view removeFromSuperview ]; :-)
Does it work better ?
Edit :
Edit bis : han, it's my fault. You need to remove controller and add another one in the app delegate and not in your mainController (you could do it too, but no with your actual code).
You have two options :
1°) Declare all your controllers in your app delegate.
2°) Declare all your controllers in one main controller. But the main controller would be here to "control" others one.

Calling pushViewController on a UINavigationController does nothing (no crash)

I have a UINavigationController as one of the views inside a tab bar control. It looks fine, and I have a UIBarButtonItem that is supposed to load a subview. I have the button wired up to an IBAction that calls pushViewController but when I do this nothing happens. It doesn't crash or anything.. it just doesn't do anything. I've tried: using different view controllers as the subview (no luck). Does anybody have any suggestions? Here is my code:
Header file:
#import <UIKit/UIKit.h>
#import "FSSettings.h"
#import "MeasureSelector.h"
#import "Dashboard.h"
#interface DashboardNavigationController : UIViewController {
IBOutlet UINavigationController *navController;
IBOutlet UINavigationBar *navBar;
IBOutlet UIBarButtonItem *measureButton;
}
#property (nonatomic, retain) IBOutlet UINavigationController *navController;
#property (nonatomic, retain) IBOutlet UINavigationBar *navBar;
#property (nonatomic, retain) IBOutlet UIBarButtonItem *measureButton;
- (IBAction) showMeasureScreen:(id)sender;
#end
And the .m file containing the action:
// Displays the measure screen
- (IBAction) showMeasureScreen:(id)sender
{
NSLog(#"Loaded measure screen");
MeasureSelector *msel = [[MeasureSelector alloc] initWithNibName:#"MeasureSelector" bundle:nil];
[[self navigationController] pushViewController:msel animated:YES];
NSLog(#"Done.");
}
When I click the button nothing happens (but I do see the log messages). I can do this over and over with no ill effects, however.
The navigationController property of UIViewController refers to the nav controller of which the UIViewController is part of the hierarchy. If I understand the scenario correctly, DashboardNavigationController manages the view that is the container for the UINavigationController, so it makes sense that this property would be nil.
Use the outlet you created to access the nav controller from outside of the nav controller's hierarchy.

Sharing a UIView between UIViewControllers in a UITabBarController

I have a UIScrollView that houses a gallery of images the user can scroll through. This view needs to be visible on each of three separate UIViewControllers that are housed within a UITabBarController. Right now, I have three separate UIScrollView instances in the UITabBarController subclass, and the controller manages keeping the three synchronized (when a user scrolls the one they can see, programmatically scrolling the other two to match, etc.), which is not ideal.
I would like to know if there is a way to work with only ONE instance of the UIScrollView, but have it show up only in the UIViewController that the user is currently interacting with. This would completely eliminate all the synchronization code. Here is basically what I have now in the UITabBarController (which is where all this is currently managed):
#interface ScrollerTabBarController : UITabBarController {
FirstViewController *firstView;
SecondViewController *secondView;
ThirdViewController *thirdView;
UIScrollView *scrollerOne;
UIScrollView *scrollerTwo;
UIScrollView *scrollerThree;
}
#property (nonatomic,retain) IBOutlet FirstViewController *firstView;
#property (nonatomic,retain) IBOutlet SecondViewController *secondView;
#property (nonatomic,retain) IBOutlet ThirdViewController *thirdView;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerOne;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerTwo;
#property (nonatomic,retain) IBOutlet UIScrollView *scrollerThree;
#end
#implementation ScrollerTabBarController
- (void)layoutScroller:(UIScrollView *)scroller {}
- (void)scrollToMatch:(UIScrollView *)scroller {}
- (void)viewDidLoad {
[self layoutScroller:scrollerOne];
[self layoutScroller:scrollerTwo];
[self layoutScroller:scrollerThree];
[scrollerOne setDelegate:self];
[scrollerTwo setDelegate:self];
[scrollerThree setDelegate:self];
[firstView setGallery:scrollerOne];
[secondView setGallery:scrollerTwo];
[thirdView setGallery:scrollerThree];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
[self scrollToMatch:scrollView];
}
#end
The UITabBarController gets notified (as the scroll view's delegate) when the user scrolls one of the instances, and then calls methods like scrollToMatch: to sync up the other two with the user's choice.
Is there something that can be done, using a many-to-one relationship on IBOutlet or something like that, to narrow this down to one instance so I'm not having to manage three scroll views? I tried keeping a single instance and moving the pointer from one view to the next using the UITabBarControllerDelegate methods (calling setGallery:nil on the current and setGallery:scrollerOne on the next each time it changed), but the scroller never moved to the other tabs.
Thanks in advance!
Certainly you should use only one instance of your scroller view. And it will works fine without any troubles. Use method setGallery: like you did, just ensure you add your singleScrollerForAll view to view of current controller in setGallery method:
-(void)setGallery:(UIView *)aScrollerView{
[self.view addSubview:aScrollerView];
}
and call:
[firstView setGallery:singleScrollerForAll];
or
[secondView setGallery:singleScrollerForAll];
and no need to do anything in other two controllers, because when you call addSubview: the subView will be automatically removed from previous superview.