简体   繁体   中英

How do I create an xcode project with multiple targets for different platforms (iPhone & Mac OS X)?

I have written a couple Core Data iPhone apps and I've run into a consistent problem that I would expect to be a common pattern for iPhone development. Namely, I have one or more command line data loaders to create the Core Data database and then I have my iPhone app. Since the model files are shared and the loaders are a integral part of the project, I want it to be a single project.

What is the right approach to create a project with an iPhone OS target and a command line target? All my attempts have not worked well -- I have code signing, debugging, and configuration troubles.

Here's my best attempt so far:

  • Create an iPhone project
  • Add a new Cocoa Shell Tool target
  • Change the base SDK to "Current Mac OS" in the target's build configuration

At this point I have no executable. (By contrast, if you create a new Command Line Utility project then an executable is automatically associated with your target.)

If I create a Custom Executable then I have a few troubles: (1) changing the target doesn't change the executable because you can't link a custom executable to a target, (2) debugging the command line program is problematic because breakpoints set in XCode don't get registered (the chevrons at the line numbers turn orange when debugging the executable), so I have to break into the running code and then handle debugging manually from the console, (3) most frustratingly, if I create a properly provisioned distribution version of my iPhone app, then transferring the iPhone app to the device fails complaining that the provisioning profile doesn't match the Code Signing Entitlement. This is definitely not the case because I set the provisioning profile and entitlement file for only the distribution version of the iPhone target, but no matter how much fiddling I can't get the target installed on devices. (If I create a new project with identical code and code signing withOUT the command line tool then I can install an AdHoc provisioned app.)

So... is there some other pattern I should be following? Xcode configurations are serious voodoo.

OK, I think your problem need to be redefined.

As you mentioned:

Namely, I have one or more command line data loaders to create the Core Data database

Your requirement is to pre-populate the database for your core data iPhone app , and also, you want to let the tool to keep consistency with your latest Core Data models . Am I right?

If my understanding is correct. I suppose, instead of creating a dedicated command line tool to pre-populate the database, do it in the Unit Test target will be a better option.

My Solution

Here is what I'm doing with my core data iOS app.

  1. Create the project with core data support along with logic test support.
  2. Write a simple testcase to access MOC and Model to populate the database file.
  3. Meanwhile, write another testcase to read in the data file, do the heavy importing job.

2 and 3 can be integrated into one testcase if you don't have much data to import.

A few benefits

  1. You can use ⌘ + k to remove everything previously created.
  2. You can use ⌘ + u to run the testcase again and repopulate the database with data.
  3. Always access the most recent version of your core data model.
  4. Most importantly , all of these are provided by Xcode's default project template. You don't need to do any extra work to make sure both targets work well.

Be ware of few things.

  1. If you are using Xcode 4.1, I recommend you upgrade to Xcode 4.2+ or even Xcode 4.3, because Xcode 4.1, you will have some trouble to access the MOC and model file directly. (At least, based on my experience) And Xcode 4.2 support the unit test app to access the database file in your document folder directly. Later all you need to do is find the sqlite file and overwrite the one in your project.
  2. If you can not migrate to Xcode 4.2+, remember to add the core data modeling files to your logic test target, and use [NSBundle bundleForClass:{Your testcase class name}] to get the correct bundle path and thus you can load the Core Data Model and create the MOC instance.

Real Sample

You can see how I do this in my open source project on github

Here is a brief code from my testcase.

- (void)setUp
{
  [super setUp];

  // Set-up CoreData
  yourMocObj = ...;
}

- (void)tearDown
{
  // Tear-down code here.
  [yourMocObj save];
  [super tearDown];
}

- (void)test_PopulateData{
  // Get the path for the data file.
  NSString *plistPath = [[NSBundle bundleForClass:[algorithms_iOSTests class]] pathForResource:@"AlgorithmsMasterViewData" ofType:@"plist"];
  NSArray *dataArray = [NSArray arrayWithContentsOfFile:plistPath];

  NSEntityDescription *yourEntity = [NSEntityDescription entityForName:.. inManagedObjectContext:yourMocObj];

  [dataArray enumerateObjectsUsingBlock:^(NSDictionary *aCategoryDict, NSUInteger idx, BOOL *stop) {
    // Category is a custom subclass of NSManagedObject.
    Category *aCategory = [[Category alloc] initWithEntity:yourEntity insertIntoManagedObjectContext:yourMocObj];
    [aCategory safelySetValuesForKeysWithDictionary:aCategoryDict];

  }];

}

From my own experience, if your project starts off as an iOS project you are in for a world of pain, as it sounds like you have discovered. Sure, you can add OS X targets to your iPhone project, but the built executable isn't automatically added in Xcode. You can then add a custom executable, but the configuration lives in the user-specific project files which can be a dealbreaker if you're using source control and collaborating with other people. Also, as you have discovered, it doesn't integrate as well as it should with the debugger, etc.

If you want a more manageable project, I'd recommend starting out with an OS X project and then adding your iOS targets. This has worked much better for me.

This might be improved in Xcode 4, but in 3.2 these issues have been a real drag. At least you know you're not alone.

I was having the same issue. And for exactly the same reason: my main project is a coredata based iphone app, and i need a utility to load data into a coredata db.

After hunting around a little I found this website with an answer:

http://blog.vucica.net/2010/09/single-xcode-project-for-ios-and-mac-os-x.html

basically, it boils down to this: hold down the option key when you select the 'Overview' popup (where you select Active Config, Active Target, Active Exec, Active Arch). I chose "Use Base SDK" and it seemed to like it. Unfortunately you have to do it every time you switch from target to target.

It worked for me when I tried to compile the OSX target. Now I just gotta fix all the actual bugs in the app...

Note of one interesting thing.

If you make a Mac OS X app project, and add a new iOS app target, you can switch both of them! You can even compile both of Mac OS X/iOS targets.

BUT!!!

It's only for iOS device platform. If you choose simulator once, the project fixed to iOS app, never compile for Mac OS X again. (you still can choose Mac OS X app target, but it does not being compiled anymore)

So it's unusable.

One more thing...

Close your Xcode. If you see inside of .xcodeproj folder, you can see several files. And you can find a .pbxuser file. Open it with text editor, and find a line activeSDKPreference=... If there it is, erase the line, and save the file. Re open the project with Xcode. Oops! it's reset! You can compile Mac OS X target again!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM