UISplitViewController subclass in a universal app - iphone

I am building a universal app that uses a UISplitViewController for the iPad, and should work on any 3.0 device such as a 1st gen iPhone/iPod touch too. The trouble is that despite the fact that I am not actually creating any instances of UISplitViewController while the app is running on an iPhone, I still get the dreaded
dyld: Symbol not found: _OBJC_CLASS_$_UISplitViewController
Referenced from: /var/mobile/Applications/.....
Expected in: /System/Library/Frameworks/UIKit.framework/UIKit
errors in console when attempting to run on a 1st gen iPod touch. Everything works fine on iOS 4 devices though. I'm guessing the problem is that I have subclassed UISplitViewController and it chokes when reading "#interface SplitControl : UISplitViewController {" line from a .h file.
The only reason I subclassed it is to override shouldAutorotateToInterfaceOrientation method. I am doing my whole app programmatically with no IB. Would it help if I used IB to create that SplitViewController and tell it to support all orientations?
Is there a way to override shouldAutorotateToInterfaceOrientation without subclassing the controller? Any other way to hide UISplitViewController from pre-3.2 devices?

All you need to do is link UIKit.framework weakly. In General settings for your target, in the list of "Linked Libraries" change the type for UIKit.framework to "Weak" instead of "Required".

Related

Coverting an iPhone targeted app to Universal in Xcode

I have a project that was intended to be an iPhone app in first instance, but now I want it to also support iPad. I have changed project's target from iPhone to Universal, but I dont know how to manage both nib versions I need now, already having nibs designed for iPhone. I tried by loading same viewControllers with different nibs according to the device, but Im not allowed to set more than one interface control to the same outlets. Any help? I have Xcode 4.4
It's pretty easy.
For your storyboard files, just include the _iPad and _iPhone suffixes.
For example, if the original storyboard name is MyStoryboard.storyboard, you'll now have MyStoryboard_iPad.storyboard and MyStoryboard_iPhone.storyboard. You can also set the storyboard file for each device under the summary view of the project.
Then, for the.xib files, include the ~iPhone and ~iPad suffixes.
ViewController.xib becomes ViewController~iPad.xib and ViewController~iPhone.xib
To start off, you can just create a duplicate if your existing .xib files and rename them to have the iPad and iPhone suffixes. Then alter the contents of each .xib as needed.
As for the .m code, you can check device type and branch your code. My approach is to define macros that identify device type, like this:
#define isDeviceIPad (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad)
#define isDeviceIPhone (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
Then I just use these macros(which return bool values) to write code that's specific to a device type(such as placement or dimensions of a particular view etc.).
You can change only targeted device as iPhone / iPad and you can use the .xib file of iPad:
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{
//For navigate to iphone view
}
else{
//For navigate to ipad view
}
Reference
Add 1 more XiB targeted for iPad to each file and during Navigation, select the Xib after checking Device type with the code shown above

How To Port an iPad Application to the iPhone

I have an existing iPad - Application, no I want to make an universal App.
There are many Tutorials with making iPhone Apps universall, but i dont find how to make iPad apps Universal. Is there somebody having experienxce with this?
No Storyboards are used, yust normal xib.
I've readed this tutorial, and porting iPhone apps to universal seems to be better supported by xcode:
http://www.raywenderlich.com/1111/how-to-port-an-iphone-application-to-the-ipad
I would think that the basic idea would be the same, whether you were converting an iPhone app to a universal app, or an iPad app to a universal one(?)
Set the iOS application target to "Universal".
If a view controller, say, XYZViewController has an associated xib for its UI, then - when you create a xib for the iPhone interface - append ~iphone to the name of the iPhone interface and ~ipad to the iPad one, i.e. their file names are
XYZViewController~iphone.xib and XYZViewController~ipad.xib. That way the right xib will be picked up if you pass nil or #"XYZViewController" as nib name to the designated initializer for the view controller. (It's worth noting that the same IBOutlet can be hooked up to the corresponding UI elements in both xibs simultaneously.)
In code, whenever you need to use a different display metaphor that depends on the device type (say you want to use , check for the device type through the test
if ([UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone)
{ ... } else { ... }
Another place where you might want to use this test is in VC's shouldautorotatetointerfaceorientation: method.

iOS universal app xcode 4 starter tips

I'm trying to start a universal app using Xcode and I'm totally lost. I started the universal Window based app from the templates. I'm trying to have a UITableViewController for the iPhone, and a UISplitViewController for the iPad. I see 3 appDelegates, and did read this post http://www.kotancode.com/2011/04/05/ios-universal-apps/ , but I'm still really confused. I started by creating a UIViewController subclass in the iPadAppDelegate folder with a .xib. Nothing is in the file yet. Then in the iPadAppDelegate.h:
#property (nonatomic, retain) IBOutlet HomeViewController_iPad *homeViewController;
Dragged a UIViewController in the MainWindow_iPad.xib, changed the class to HomeViewController, and tried dragging an outlet from the MainWindow to the UIViewController and I am not able to connect the HomeViewController.
I thought I could do somthing like this for the iPhoneAppDelegate as well, but I believe I am missing something from the Universal App Template. Can someone give me some advice on how these 3 appDelegates work and how I can get started? TIA
Universal Apps are really simple once you grasp how they work.
The reason there are three AppDelegates is that you usually have one that is the base class for an iPhone and iPod specific app delegate. The entry-point into your iPhone or iPad Application is based on the configuration in your .plist file, if you select the project in xCode 4 it will show you a graphical configuration dialog that will allow you to change those properties. The so called "Main Interface" is independently selectable for iPhone and iPad in the respective deployment section. The Main Nib file does contain a serialized version of the device specific app delegate, which will then be "woken up" when the application is loading. This process is triggered from your Main() method when
UIApplicationMain(argc, argv, nil, nil)
is called. UIApplicationMain does take care of loading the proper NIB file, based on the device it is run on.
Thats all there is.

iPhone App view fails to load in iPad but loads in iPhone simulator

I am simulating an "iPhone-only" app in iPad. The binary simulates fine in the iPhone simulator, but when attempting to simulate in the iPad, the initial background image appears, but then the screen just goes black. (Xcode v4.1, SDK 4.1)
The app has only one view, which is controlled by a single custom UIViewController. (SoloViewController) The only view managed by SoloViewController is contained in a "detached" nib called "mainview.xib".
I initialize the SoloViewController in my AppDelegate like so:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
SoloViewController *vc = [[SoloViewController alloc] initWithNibName:#"mainview" bundle:[NSBundle mainBundle]];
self.soloViewController=vc;
[vc release];
[window addSubview:[soloViewController view]];
[window makeKeyAndVisible];
}
My Info.plist file has the "Main nib file base name" set to "MainWindow", which I believe is the default Xcode gives you when you first create a ViewController-based project. Anyway, I just left that as-is. However, when attempting to simulate in iPad, the log says:
Failed to load NSMainNibFile MainWindow.
iPhone simulator and hardware have no problem with this...
If I set the "Main nib file base name" key to "mainview" to use the xib file for the view, I get this error:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<UIApplication 0x7a01270> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key view.'
I've double-checked the xib in IB and all of the outlets are properly defined and connected to SoloViewController.h & SoloViewController.m. What am I doing wrong here!?
Also - if I leave the NSMainNibFile blank, then the iPhone simulator just comes up with a black screen. (no errors in log)
As it turns out the project, in this case requires a MainWindow.xib file. In my case, I had inadvertently removed this file from the original project template and thought it was ok, since it simulated and ran fine in hardware. (iPhone) The MainWindow.xib file requires a File's Owner of type "UIApplication", First Responder of type "UIResponder", an App Delegate of a custom type pointing to your application delegate. (name will vary depending on what you've named your project) Lastly there is a Window of type UIWindow. All of these are default settings, with exception of the App Delegate.
Once I included a xib configured this way, the app loads as expected in both iPhone & iPad simulators. (Still not clear as to why the iPad simulator treats the absence of the MainWindow.xib file differently)
Similar behavior can happen when you reference constants in your code (or via IB code-generation) that are defined in iOS 4x or later, while the iPad runs 3.2x, and knows nothing of these key definitions.
Make sure your target has the iOS Deployment Target set to iOS 3.2 and the Base SDK to 4.1. If you changed these values, do a clean before recompiling. Unfortunately, I don't think you'll see a compiler warning in this case.
Hope that helps.

How do I make a universal iPhone / iPad application that programmatically uses UISplitViewController and UINavigationController?

I couldn't find a good answer anywhere to this. I am using a UINavigationController for my iPhone app, with everything is generated programmatically, nothing in Interface Builder. I am trying to port my app to iPad, using a UISplitViewController and my existing UINavigationController, but I am not sure where I should have the logic of my program separating the view controllers for iPhone or iPad.
Do I set up my main file to use a different app delegate or do I use the same app delegate and have the user interface conditionally set up within it?
Besides this, whenever I try to compile my app on the simulator it does not recognize the UISplitViewController or even the condition in which I check if the class exists.
Can please someone put me in the right direction, remembering that I am not using any xibs?
If you want to see an example of a completely programmatic iPhone / iPad interface that uses a split view, you can download the source code of my application Molecules.
Within that application, I use one application delegate, but I set up the interface differently depending on which user interface idiom is present (iPad or iPhone). For the iPhone, I instantiate a root view controller which manages the appropriate interface for that device. For the iPad, I first create a UISplitViewController and attach it to the root window, then create my iPad-specific root view controller and place it as the detail view of the split view controller (with a navigation controller that I use for item selection as the left-hand controller for the split view).
Again, I recommend looking at that application project to see how I set this up programmatically. The code's available under a BSD license, so you can copy and paste this into your own application if you'd like.
As far as the compilation errors you're getting, you will need to migrate your application target to be a universal application using the "Upgrade Current Target for iPad" menu option. Once that has completed, set your build SDK to 3.2. Go to your application's build settings and set its Deployment Target to the earliest OS you want to support with your application (with 3.0 being the farthest back you can go).
Finally, you will need to weak-link UIKit. For how to do that, see my answer here. Weak linking of frameworks is no longer necessary if you are building using the iOS 4.2 or later SDK. Simply check for the presence of the appropriate classes at runtime by seeing if their +class method returns nil.