There are three main levels in Xcode’s configuration hierarchy:
- Targets — each one defines the set of source files & other resources which should be compiled as a single app, library or framework
- Build configurations — each one defines a set of build settings which affect how targets are compiled — preprocessor macros, linker flags, compiler flags etc.
- Schemes — each one defines what target & build configuration to build and how to further refine the build & run process
When you decide which level of configuration to use, you have to think what aspect of your product you are configuring. API endpoints are runtime configuration options which don’t generally have any compile-time effect to the code.
You can use target per endpoint, but it will lead to maintenance nightmare — each new source file will need to be added to several targets, your Xcode project file diffs will be a huge mess all the time etc.
You can use build configuration per endpoint as author suggests. It’s better option than using targets, but it’s still means too heavy maintenance because you are configuring runtime options with compile-time tools, and it will lead to problems with Xcode subprojects which are using different set of build configurations (since build configuration affects directory paths where stuff gets built and you’ll easily run into search path issues).
Personally I would recommend using Xcode schemes & your own JSON configuration files as much as possible. Each JSON file contains configuration settings like API endpoints, tokens and keys of various SDKs (Flurry, HockeyApp), your bundle ID and name of your icon asset. That JSON file gets bundled with the app & parsed at runtime. To get environment-specific icon & bundle ID, each scheme runs a pre-build script which generates a .xcconfig file, which then is read by the Xcode’s build phase to get correct icon & bundle ID.