I see similar questions already here and Google but none answer my actual question. I'd like to have a single NIB for both iPhone and iPad. The NIB itself is supposed to have an empty view only. Everything that should go into the view is done programmatically. I check if device is iPhone/iPad and then calculate and set the layout. A little more work but for the required task this the best solution for me.
But when adding a new view through "New File... -> User Interface -> View" I'm asked for the device Family. The choices are of course iPhone OR iPad. But I want the view to work on both devices, kind of generic.
I tried the iPhone view and it actually works on both devices, iPhone AND iPad. So it seems that everything is fine. My question is more generic asking if it is ok to re-use the iPhone view also for iPad. Shall I do it differently? Any better solution?
Please understand that I really want to work with a single view and programmatically, so solutions to use separate views for each device and use IB shall be left out please!!!
Thanks
If you are creating everything programmatically, there is no need for a nib at all to create an empty view.
Your UIViewController subclass should look like this
#implementation MyViewController
-(void)loadView
{
//Do not call [super loadView] in your implementation.
//The super implementation loads the nib based on the nibName and nibBundle properties.
UIView * view = [[UIView alloc] init];
//Add subviews, etc
//You must assign a UIView object to the view property before loadView completes
self.view = view;
}
#end
You can instantiate the view controller using any format below:
MyViewController * controller = [[MyViewController alloc] initWithNibName:nil bundle:nil];
MyViewController * controller = [[MyViewController alloc] init];
MyViewController * controller = [MyViewController new];
First of all you can do this thing With AutoResize > LINK
and if it become complex for you then you can use below function and do it yourself programmatically.
-(int)setScreenOf
{
int size=0;
if((UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad))
{
//ipad
size=3;
}
else
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height ==568)
{
size=2;
// code for 4-inch screen
}
else
{
size=1;
// code for 3.5-inch screen
}
}
return size;
}
OR if you want to do a Device version Specific code then try this.
-(NSString *)deviceVersion
{
size_t size;
sysctlbyname("hw.machine", NULL, &size, NULL, 0);
char *answer = (char*)malloc(size);
sysctlbyname("hw.machine", answer, &size, NULL, 0);
NSString *platform = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding];
free(answer);
NSLog(#"Platform: %#", platform);
return platform;
}
Related
I am using below code for popover for iPad apps. Its working fine for iPad apps but when i use same code for iPhone its getting crash near
" UIPopoverController* removeDefaultPopover=[[UIPopoverController alloc]initWithContentViewController:NavController];"
Can any help me to come out of this..
UIViewController *removeDefaultController = [[UIViewController alloc] init];
UIView *removeDefaultView = [[UIView alloc] init];
removeDefaultController.view = removeDefaultView;
removeDefaultController.contentSizeForViewInPopover = CGSizeMake(100, 100);
UINavigationController *NavController=[[UINavigationController alloc]initWithRootViewController:removeDefaultController];
UIPopoverController* removeDefaultPopover=[[UIPopoverController alloc]initWithContentViewController:NavController];
UIBarButtonItem *edit = [[UIBarButtonItem alloc] initWithTitle:#"EDIT" style:UIBarButtonItemStyleBordered target:self action:#selector(editDefaultLanguage)];
[removeDefaultController.navigationItem setRightBarButtonItem:edit animated:YES];removeDefaultPopover.delegate=self;
[removeDefaultPopover presentPopoverFromRect:CGRectMake(0, 0, 100, 100) inView:self.view permittedArrowDirections:NO animated:YES];
removeDefaultView.backgroundColor=[UIColor redColor];
From the documentation:
Popover controllers are for use exclusively on iPad devices.
Attempting to create one on other devices results in an exception.
You have to implement similar functionality by yourself.
According to Mark Sands UIPopoverController contains the following code:
- (id)initWithContentViewController:(UIViewController *)viewController {
if (([[UIDevice currentDevice] respondsToSelector:#selector(userInterfaceIdiom)]) {
if ([[UIDevice currentDevice] userInterfaceIdiom] != UIUserInterfaceIdiomPad) {
if ([UIPopoverController _popoversDisabled]) {
[NSException raise:NSInvalidArgumentException format:#"-[UIPopoverController initWithContentViewController:] called when not running under UIUserInterfaceIdiomPad."];
}
}
}
...
}
+ (BOOL)_popoversDisabled {
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];
if ([bundleIdentifier isEqualToString:#"com.apple.iBooks"] || [bundleIdentifier isEqualToString:#"com.apple.mobilesafari"] ||
[bundleIdentifier isEqualToString:#"com.apple.itunesu"] || [bundleIdentifier isEqualToString:#"com.apple.Maps"]) {
return NO;
}
return YES;
}
As you can see UIPopoverController is enabled for Apple's applications.
You can create UIPopoverController subclass and implement + _popoversDisabled in the following way:
+ (BOOL)_popoversDisabled {
return NO;
}
Or use method swizzling for it.
You can't use "UIPopOverController" for iPhone apps as this is intended for iPad devices only. Alternatively you can use CMPopTipView which is work in similar way as UiPopoverController does. You can check this control on https://github.com/chrismiles/CMPopTipView
I have used this control in my previous app and it works great.
As mentioned previously, UIPopoverController is not currently enabled in iPhone applications. However, if you would still like the functionality I would recommend WEPopover. Here's how easy it is to use:
SettingsViewController *viewController = [[SettingsViewController alloc]init];
self.popover = [[WEPopoverController alloc]initWithContentViewController:viewController];
[self.popover presentPopoverFromRect:self.settingsButton.frame
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
All the correct lifecycle methods are called and it has several convenience methods as well for presenting, dismissing, etc. I've used it in several projects and have been very satisfied with it.
The only thing to watch out for when using this is to make sure that you keep a strong reference to your popover object (thus, in my example you see me use self.popover instead of an instance variable).
I need to use different xib files for portrait and landscape. I am not using Auto Layout but I am using iOS6. (See my previous question if you care why.)
I'm following Adam's answer to this question modified with amergin's initWithNib name trick, modified with my own iPhone/iPad needs. Here's my code:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[[NSBundle mainBundle] loadNibNamed:[self xibNameForDeviceAndRotation:toInterfaceOrientation]
owner: self
options: nil];
[self viewDidLoad];
}
- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation
{
NSString *xibName ;
NSString *deviceName ;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
deviceName = #"iPad";
} else {
deviceName = #"iPhone";
}
if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
{
xibName = [NSString stringWithFormat:#"%#-Landscape", NSStringFromClass([self class])];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#-Landscape", NSStringFromClass([self class]), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
} else {
xibName = [NSString stringWithFormat:#"%#", NSStringFromClass([self class])];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#", NSStringFromClass([self class]), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
}
}
and of course I'm doing:
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
in my view controller and:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return (UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortraitUpsideDown);
}
in my delegate.
I have two problems which may be related. First, the easy one. I do not rotate upside down. I have all all the proper bits turned on in xcode for both iPad and iPhone. This may be a separate issue or it may be the core of my problem.
The real problem is that when I rotate to landscape mode my xib is replace but the view is off by 90 degrees.
Here's what my 2 xib's look like. (I've colored them garishly so you can see that they are different.)
and
and you can see when I run it (initially in Landscape mode) that the landscape xib is correct.
when I rotate to portrait it is also correct
but when I rotate back to landscape the xib is replaced but the view is off by 90 degrees.
What's wrong here?
I've been following probably the same path as Paul Cezanne did last year. Not sure if he tried this or not, but I solved the original issue (stated in this question) by just making my root controller a navigation controller instead of my view controller class. Since I'm using an "empty project" template and XIB files, this meant changing the normal:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
self.window.rootViewController = self.viewController;
inside AppDelegate.m, to this instead:
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.viewController];
navigationController.navigationBar.hidden = YES;
self.window.rootViewController = navigationController;
That is, I just created a generic UINavigationController and set that as the root view controller.
I'm not sure if this will cause other problems, and there is probably a way to figure out (maybe you would need the source code though) what UINavigationController does that UIViewController doesn't. Could be as simple as one extra setNeedsLayout type of call in the right place. If I figure it out, I'll edit this answer for future readers.
Credit goes to Sakti's comments on Easiest way to support multiple orientations? How do I load a custom NIB when the application is in Landscape? which I shouldn't have ignored the first time I read them:
i added the view controller to navigation controller and presented it
which made it work as intended
Edit: Added extra line to example code to hide navigation bar, since most people following this issue will not want that.
This is how I do it and it works on iOS 5+:
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkBagRotation)
name:UIApplicationDidChangeStatusBarOrientationNotification
object:nil];
[self checkBagRotation];
}
- (void)checkBagRotation {
orientation = [UIApplication sharedApplication].statusBarOrientation;
if(orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
[[NSBundle mainBundle] loadNibNamed:#"Controller-landscape"
owner:self
options:nil];
} else {
[[NSBundle mainBundle] loadNibNamed:#"Controller-portrait"
owner:self
options:nil];
}
I'm answering my own question here pasting from the full article on my iOS blog at http://www.notthepainter.com/topologically-challenged-ui/
I had a friend help me out, he used 2 views in one xib file with IBOutlets for portrait and landscape view and he toggled between them the device rotated. Perfect, right? Well, no, when you have 2 views in a XIB you can’t hook up your IBOutlets to both places. I had it working visually but my controls only worked in one orientation.
I eventually came up with the idea of using a orientation master view controller that loaded container view controllers when the device rotated. That worked fine. Lets look at the code:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
if (_timerViewController) {
[_timerViewController.view removeFromSuperview];
[_timerViewController willMoveToParentViewController:nil];
[_timerViewController removeFromParentViewController];
self.timerViewController = nil;
}
self.timerViewController = [[XTMViewController alloc] initWithNibName:
[self xibNameForDeviceAndRotation:interfaceOrientation withClass:[XTMViewController class]]
bundle:nil];
// use bounds not frame since frame doesn't take the status bar into account
_timerViewController.view.frame = _timerViewController.view.bounds = self.view.bounds;
[self addChildViewController:_timerViewController];
[_timerViewController didMoveToParentViewController:self];
[self.view addSubview: _timerViewController.view];
}
The addChildViewController and didMoveToParentViewController should be familiar if you read my previous blog entry on Container View Controllers. There are two things to notice above those calls though. I’ll deal with the second one first, I set the child view controller’s frame and bounds from the parents bounds, not frame. This is to take account of the status bar.
And notice the call to xibNameForDeviceAndRotation to load the view controller from its xib file. Lets look at that code:
- (NSString *) xibNameForDeviceAndRotation:(UIInterfaceOrientation)toInterfaceOrientation withClass:(Class) class;
{
NSString *xibName ;
NSString *deviceName ;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
deviceName = #"iPad";
} else {
deviceName = #"iPhone";
}
if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) ) {
xibName = [NSString stringWithFormat:#"%#-Landscape", NSStringFromClass(class)];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#-Landscape", NSStringFromClass(class), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
} else {
xibName = [NSString stringWithFormat:#"%#", NSStringFromClass(class)];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
xibName = [NSString stringWithFormat:#"%#_%#", NSStringFromClass(class), deviceName];
if([[NSBundle mainBundle] pathForResource:xibName ofType:#"nib"] != nil) {
return xibName;
} else {
NSAssert(FALSE, #"Missing xib");
return nil;
}
}
}
return nil;
}
There’s a lot going on here. Let’s go over it. I first determine if you are on an iPhone or an iPad. The xib files will have iPhone or iPad in their names. Next we check to see if we are in landscape mode. If we are, we build a test string from the class name, using class reflection via NSStringFromClass. Next, we use pathForResource to check to see if the xib exists in our bundle. If it does, we return the xib name. If it doesn’t, we try again also putting the device name into the xib name. Return it if it exists, assert a failure if it doesn’t. Portrait is similar except by convention we don’t put “-Portrait” into the xib name.
This code is useful enough and generic enough that I’ll put it in my EnkiUtils open source project.
Since this is iOS6 we need to put in the iOS6 rotation boilerplate code:
- (BOOL) shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
Curiously we also need to manually call willAnimateRotationToInterfaceOrientation on iPads. iPhones get a willAnimateRotationToInterfaceOrientation automatically but iPads do not.
- (void) viewDidAppear:(BOOL)animated
{
// iPad's don't send a willAnimate on launch...
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[self willAnimateRotationToInterfaceOrientation:[[UIApplication sharedApplication] statusBarOrientation] duration:0];
}
}
So, are we finished? Embarrassingly no. You see, when I coded the XTMViewController class I broke the Model-View-Controller design pattern! This is easy to do, Apple already helps us by putting the View and the Controller into the same class. And it is so easy to carelessly mix in Model data in the VC’s .h file. And I had done exactly that. When I run the above code it work brilliantly, I could rotate it all day and the UI was correct in both orientations. But what do you think happened when I rotated the device while my exercise timers were running? Yup, they were all deleted and the UI reset to the initial state. This was not at all what I wanted!
I made a XTMUser class to hold all the timing data, I put all the NSTimers into the XTMOrientationMasterViewController class and then I made a protocol so the XTMOrientationMasterViewController could respond to UI taps in the XTMViewController class.
Then I was done.
I am just working on iOS app and I want to make it universal for both iPhones and iPads. This is done and works without any problems:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController_iPhone = [[ViewController_iPhone alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
} else {
self.viewController_iPad = [[ViewController_iPad alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
if (self.viewController_iPhone == nil)
self.window.rootViewController = self.viewController_iPad;
else
self.window.rootViewController = self.viewController_iPhone;
There is a view for each controller (ViewController_iPad.xib, ViewController_iPhone.xib). It doesn't matter which view is loaded in my problem. In a view there is a subview added (UIScrolView). And in this ScrollView there are two views from xib:
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:#"SubView1" owner:self options:nil];
UIView *view = [nibContents objectAtIndex:0];
view.frame = CGRectMake(2, 0, scrollView.frame.size.width - 2, scrollView.frame.size.height);
[scrollView addSubview:view];
nibContents = [[NSBundle mainBundle] loadNibNamed:#"SubView2" owner:self options:nil];
view = [nibContents objectAtIndex:0];
view.frame = CGRectMake(scrollView.frame.size.width + 2 , 0, scrollView.frame.size.width - 4, scrollView.frame.size.height);
[scrollView addSubview:view];
(This code is in iPad/iPhone controller). Still everything is OK. But I don't know how to set owners (in IB) of these subviews that are shown in ScrollView. These subviews are in ScrollView which is in a main view so I want to set owners of these subviews as iPad/iPhone controller. But as a owner can be only one class. Can you tell me how to set owners if I have two main controllers and I don't know which one will be loaded in runtime. Thank you.
EDIT: I have another question: I have ViewController_iPhone. It has a View property and this property is assigned to the "root" view in the main view in ViewController_iPhone (.xib). Can I assign this view property also to subview view? Because I got EXC_BAD_ACCESS error if I assign view property of ViewController_iPhone to a "root" view of subview in IB.
Looks like you need to use a class cluster. This will abstract the iPhone/iPad instantiation, so you don't explicitly need to instantiate one of the two.
You can read a bit about class clustering in the Apple documentation:
http://developer.apple.com/library/ios/#documentation/general/Conceptual/DevPedia-CocoaCore/ClassCluster.html
It boils down to creating a master view controller which will handle the allocation of iPhone or iPad subclasses based on the current device.
You should override the ViewController alloc class method:
+ (id)alloc {
NSString *classString = NSStringFromClass([self class]);
NSString *append = nil;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
append = #"_iPhone";
} else {
append = #"_iPad";
}
NSString *subClassString = [classString stringByAppendingString:append];
id subClass = NSClassFromString(subClassString);
id object;
if (subClass && ![self isKindOfClass:[subClass class]]) {
object = [subClass alloc];
} else {
object = [super alloc];
}
return object;
}
This way you can just allocate the ViewController class and at runtime the correct class definition will be used to instantiate your view controller.
This will allow you to use the ViewController class as the owner in IB provided that you create an abstraction of iPhone and iPad interfaces and define it in their super class.
This question already has answers here:
iOS: Using device modifiers for loading xib files?
(4 answers)
Trouble with loading a separate XIB for iPad or iPhone
(3 answers)
Closed 9 years ago.
Sorry Guys in advance, I know there are already plenty similar questions are available. I tried all solutions but didn't work any of them for me.
I'm Using Xcode 4.5.2 and using two xibs for iphone5/ios6 1> RootViewController5 and for all other devices 2> RootViewController these both nib file has single ViewController named RootViewController.In both the nib file's File owner I have selected RootViewController class in Custom class inspector.
Now in ViewDidLoad method I'm trying to load two nibs like this
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
UIViewController *viewController3;
if(result.height == 480)
{
viewController3 = [[[UIViewController alloc] initWithNibName:#"RootViewController" bundle:nil] autorelease];
}
if(result.height == 568)
{
viewController3 = [[[UIViewController alloc] initWithNibName:#"RootViewController5" bundle:nil] autorelease];
NSLog(#"iphone 5 123");
}
}
I have tried below code as well
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
RootViewController *viewController3;
if(result.height == 480)
{
viewController3 = [[[UIViewController alloc] initWithNibName:#"RootViewController" bundle:nil] autorelease];
}
if(result.height == 568)
{
viewController3 = [[[UIViewController alloc] initWithNibName:#"RootViewController5" bundle:nil] autorelease];
NSLog(#"iphone 5 123");
}
}
But no luck. Please advise where I'm getting it wrong.
Thanks
Mayur
I suggest you do something like this instead:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone){
if([UIScreen mainScreen].bounds.size.height == 568.0)
{
//Use iPhone5 VC
self = [super initWithNibName:#"RootViewController-568h" bundle:nibBundleOrNil];
}
else{
//Use Default VC
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
}
}
return self;
}
That is if your RootViewController is named just that. And by doing it this way you save yourself from future crashes if they should decide to add another size of an iPhone/iPod.
As you are using two if statements, if neither is true it will crash the app and is really not good coding.
A good practice is to always try and think ahead and plan for the future, if they should release another screen size it wouldn't look good but would at least not crash.
The obvious problem I see from your description is that you set the custom class to "RootViewController" in your nib, but you are actually instantiating a "UIViewController" in your code.
What you should have done is:
viewController3 = [[[RootViewController alloc] initWithNibName:#"RootViewController" bundle:nil] autorelease];
Otherwise, when the runtime loads your nib, and is trying to set up those RootViewController specific outlets in your nib, the runtime won't be able to find those in a vanilla UIViewController, and so crashes.
I don't think that you've to use two different .xib's for iPhone5 & iPhone4, 4S etc. If you want to change the sizes of your images, labels, buttons etc., that's why Spring and Structs are used for. You can also set the sizes programmatically by using the code you've written in your question (in your .m files....... )
I also have done that mistake before. When i used to run the program, i always came up with the error
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException',
reason: '-[UIViewController _loadViewFromNibNamed:bundle:] loaded the "View" nib but
the view outlet was not set.' *** First throw call stack:(0x1c93012 0x10d0e7e 0x1c92deb
0xf58c8 0xf5dc8 0xf5ff8 0xf6232 0x453d5 0x4576f 0x45905 0x4e917 0x2b7f 0x12157 0x12747
0x1394b 0x24cb5 0x25beb 0x17698 0x1beedf9 0x1beead0 0x1c08bf5 0x1c08962 0x1c39bb6
0x1c38f44 0x1c38e1b 0x1317a 0x14ffc 0x25fd 0x2525 0x1)libc++abi.dylib:
terminate called throwing an exception
This is because " nib outlet was not set"
So, i think you should either use Springs and structs or do programmatically..
I would recommend you to :
use story board, instead of XIB files when you instantiate a VC, ex:
myVC* vc = [self.storyboard instantiateViewControllerWithIdentifier:#"myVCStoryBoardID"];
[self.navigationController pushViewController:vc animated:YES];
This helps keep VC design under the same roof, and to use powerful features of storyboarding.
Then to check that Auto-layout is active on your story board controllers, and insure that the constrains on one, say, label, map to the boundary of other elements (very important), above and below. This materialises by dotted blue lines when you move it. In most case, the run-time will be able to align everything, regardless of screen height.
I understand that there might be some nasty edge cases in this regards, so you might have to adjust stuff manually. Unless you have complex graphics, it's always possible to work with Y coordinate in the [0,1] interval, and once you have to set a frame, use [[UIScreen mainScreen] bounds].size to get the appropriate value, rounded to the nearest integer.
If all the above fails, then you might have to create separate VC, but in my view, that's not really what the SDK is intended for.
good luck!
Wow, I was such a fool, I didn't realise that I wasn't loading the Nib Properly. Only thing I was wrong with is This line of code
I wrote
viewController3 = [[[UIViewController alloc] initWithNibName:#"RootViewController5" bundle:nil] autorelease];
instead of
[[NSBundle mainBundle] loadNibNamed:#"RootViewController5" owner:self options:nil];
So My Final code is look like this and Works absolutely fine
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480)
{
// iPhone Classic
[[NSBundle mainBundle] loadNibNamed:#"RootViewController" owner:self options:nil];
}
if(result.height == 568)
{
// iPhone 5
[[NSBundle mainBundle] loadNibNamed:#"RootViewController5" owner:self options:nil];
}
}
Thanks to this link Link to the right Answer
I am have an issue with my scrollview which holds multiple views. I think the problem is that subviews are being released. I have buttons in the subviews and when I click the buttons I get this error, [GraphDisplayViewController performSelector:withObject:withObject:]:
message sent to deallocated instance
. If there is only one subview then I can just use a property and this works, but since the number of subviews varies(one or more), it does not work and I don't know how to solve this.
I currently load all the views at once in the beginning. I'm working on only loading one subview at a time and assigning the property to that view, but I'm not sure if that will work.
My layout is as follows, a parent view(DetailViewController) contains a scrollview, I add views(GraphDisplayViewController) to the scrollview, the subviews each load a view(GraphView).
Any help or advice would be greatly appreciated. If you need any more details please let me know. Thank you for your time.
Code sample of how I add the subviews,
DetailViewController
- (void)loadScrollViewWithPage:(int)page
{
if (page < 0) return;
if (page >= pageControl.numberOfPages) return;
subView = [viewControllers objectAtIndex:page];
NSString *description;
NSString *packsize;
if ((NSNull *)subView == [NSNull null])
{
subView = [[GraphDisplayViewController alloc] initWithNibName:#"GraphDisplayViewController" bundle:nil];
[viewControllers replaceObjectAtIndex:page withObject:subView];
subView = [[GraphDisplayViewController alloc] init];
subView.molecule = moleculeName;
subView.description = description;
subView.dataArray = moleculePrices;
}
else
{
return;
}
// add the controller's view to the scroll view
if (nil == subView.view.superview)
{
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
subView.view.frame = frame;
[scrollView addSubview:subView.view];
}
}
UPDATE
There was a mistake in the code, testing to see if that solves anything
subView = [[GraphDisplayViewController alloc] initWithNibName:#"GraphDisplayViewController" bundle:nil];
[viewControllers replaceObjectAtIndex:page withObject:subView];
subView = [[GraphDisplayViewController alloc] init]; <- Mistake
you are not retaining the GraphDisplayViewController assigned to subView variable. and hence you are loosing it at some point of time.
as we can see you are fetching the subView object like subView = [viewControllers objectAtIndex:page];
then you should also store it in viewControllers (though i am not sure what logic you have implemented but in ur code for each allocated subView this must be executed : [viewControllers replaceObjectAtIndex:page withObject:subView]; and you need to be sure that viewControllers variable is also retained for everything to work smoothly.) array so that it can be retained to avoid the crash you are facing.
I hope this will work for you..best of luck
There was a simple error in my code, I init the view twice.
subView = [[GraphDisplayViewController alloc] initWithNibName:#"GraphDisplayViewController" bundle:nil];
subView = [[GraphDisplayViewController alloc] init]; <- Mistake