30

I have written an iPhone and iPad universal app which runs fine in the iPad simulator on Xcode, but I would now like to test the iPhone functionality. I seem unable to run the iPhone simulator with this code as it always defaults to the iPad?

Instead I tried to run on the device and as it begins to run I get the following error:

dyld: Symbol not found: _OBJC_CLASS_$_UISplitViewController
  Referenced from: /var/mobile/Applications/9770ACFA-0B88-41D4-AF56-77B66B324640/Test.app/Test
  Expected in: /System/Library/Frameworks/UIKit.framework/UIKit in /var/mobile/Applications/9770ACFA-0B88-41D4-AF56-77B66B324640/Test.app/TEST

As the App is built programmatically rather than using XIB's, I've split the 2 device logics using the following lines in the main.m method:

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate_Pad");
}
else
{
    retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate_Phone");
}

From that point forth they use different AppDelegates and I've checked my headers to ensure the UISplitView is never used nor imported via the Phone logic.

How do I avoid this error and is there a better way to split the universal logic paths in this programmatically-created app?

Andrey Zverev
  • 4,409
  • 1
  • 28
  • 34
andybee
  • 1,142
  • 3
  • 15
  • 26
  • You done right except direct checking if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) check this link for nice utility method http://cocoabugs.blogspot.com/2010/09/checking-device-is-ipad-or-iphone-in.html –  Sep 15 '10 at 04:45
  • And how to find references to new APIs that didn't exist pre-4? Great answer [here](http://stackoverflow.com/questions/7790497/iphone-app-developed-with-sdk-4-2-requires-backward-compatibility-with-ios-3-1) – Steve Rogers Nov 25 '11 at 05:21

3 Answers3

66

That error is being triggered because you didn't weak-link the UIKit framework. The UIKit framework in iPhone OS 3.2 added the UISplitViewController, and if you link it in as normal your application will assume those symbols exist on 3.0, where they don't.

To weak-link a framework, find your application target in Xcode, inspect it, and go to the General tab. At the bottom of that tab should be a list of frameworks, with a column for Type. Change the Type for UIKit from Required to Weak and rebuild your application. That should take care of the runtime errors.

Your conditional logic is sound, but I tend to share an application delegate and do the interface-specific layout further down the line.

(Update: 12/21/2011) As of iOS 4.2, you should no longer need to weak link frameworks to prevent errors like this. As Marco Arment describes, if you build with iOS 4.2 or later and target down to iPhone OS 3.1+, individual classes are now weak linked and should have their +class method return nil if the class does not exist on the currently running version of the OS.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • Great, many thanks. I do find the documentation a little lacking in substance in this area. – andybee Apr 13 '10 at 10:10
  • 1
    @andybee: The iPad Programming Guide has a good section on creating universal applications: http://developer.apple.com/iphone/library/documentation/General/Conceptual/iPadProgrammingGuide/StartingYourProject/StartingYourProject.html#//apple_ref/doc/uid/TP40009370-CH9-SW2 , and the Introducing Universal Applications for iPhone OS (PDF) is worth reading, as well: http://devimages.apple.com/iphone/resources/introductiontouniversalapps.pdf – Brad Larson Apr 13 '10 at 12:24
  • check this link for nice utility method http://cocoabugs.blogspot.com/2010/09/checking-device-is-ipad-or-iphone-in.html –  Sep 15 '10 at 04:47
  • 6
    In XCode 4.2 this is at target -> Build Phases -> Link Binary with Libraries -> change framework from "Required" to "Optional". – fabb Oct 21 '11 at 09:59
  • You don't need to weak-link if you get the class dynamically using `NSClassFromString()` – user102008 Oct 21 '11 at 22:32
  • By your logic, we should always weak-link all frameworks, including UIKit, Foundation, etc. and never have to worry about new symbols? – user102008 Oct 21 '11 at 22:32
  • @user102008 - There is a performance penalty to weak linking, I believe resulting in a slowdown on startup. Weak linking only the necessary frameworks was recommended. In the meantime, iOS 4.2 made it so that if you target greater than iPhone OS 3.1, you now no longer need to weak-link at the framework level: http://www.marco.org/2010/11/22/supporting-older-versions-of-ios-while-using-new-apis – Brad Larson Oct 21 '11 at 22:37
  • @Brad: Great solution, dude, thank you so much! Had the same problem and no clue how to deal with ... – Leo Chapiro Aug 26 '13 at 09:19
4

I was having a very similar error and it was driving me nuts! :-) Searching for hours and couldn't figure it out...

Like you said, everything was fine when running in the iPad Simulator but when trying to test the App on the iPhone with iPhone OS 3.1.2 it would not even start but crash with the following error message:

mi_cmd_stack_list_frames not enough frames in stack

By checking nearly every line of code I realised that the allocating of 3.2 classes like UIPopoverController or UISplitViewController (already inside forked iPad-specific code) was causing the problem.

So instead of i.e.:

infoPopover = [[UIPopoverController alloc] initWithContentViewController: infoNavController];

i would write

infoPopover = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController: infoNavController];

and that solved my problem! (Debugging can be so hard if the error message gives you no clue about where the bug could possibly be found...)

xoconoxtle
  • 135
  • 1
  • 8
  • 1
    BTW: the weak-linking of the UIKit-Framework as mentioned above by Mr. Larson seems to be the easier and better way of solving this issue – xoconoxtle Apr 12 '10 at 19:48
  • The above is more likely the preferred way of doing it, but nonetheless this method does work. – andybee Apr 13 '10 at 10:10
  • I believe that this is a better answer than weak-linking an entire framework, because there is an overhead to weak-linking – user102008 Oct 21 '11 at 22:30
0

Xcode 8.3, iPad 2 (non retina), Swift 3 code

What helped for me was:

  • restart Xcode
  • do a 'Product -> Clean' ShiftCommandK
  • rebuild the project
CousinCocaine
  • 591
  • 6
  • 20