Dividing a project into multiple Xcode project files - objective-c

An iPad project I have been working on has become bloated with a huge number of files. The application is a prototype and we are considering ways to prevent this when we rewrite it.
One of the members of our team suggests dividing all of the components into separate Xcode projects which will be included in a master Xcode project.
Is this a good idea? What are the reasons, if any, to avoid dividing features/components/controls into separate Xcode projects?

You can add a subsidiary project file to a master project file in Xcode. Just choose "Add File" and add it. When Xcode builds the master it will build the subsidiary as well if needed.
I use a similar system. I often break a project into sub projects just so I can focus on and enforce encapsulation. I write the data model first, then add the app delegate, then specific UI elements. I add each project to the next in turn. This also allows me to go back and change things without as much risk of breaking.
Really, a properly designed objective-c app should be easy to decompose into multiple project. Ideally, all the components are so encapsulate that they don't need any others save the data model.

We have put some of the code in its own project, building a framework which we link against at some of the other projects. It's sometimes annoying that you won't see the implementation files of the framework code right away in another project (by cmd+clicking or cmd+shift+D, or whatever you do normally to navigate). Xcode will only show you the header, you'll have to open the other project and find your file there manually. Not a big deal, but if you look up the code often, it will bother you.
A real problem is that you change the scope of some operations. Stuff like "Find in project" will work on a different file set, which might not be what you want sometimes (trying to find where this method is called / key is used in your whole code, or something); well, there remains Finder / find, so it might be okay. Refactoring is not - all the renaming stuff just breaks, as it will change only the code of the current project, but not of projects referencing this one. If you change interfaces often, better avoid splitting up the project.
A good thing is that you will get less conflicts on your .xcodeproj files (if stored in a shared repository) as someone removing a file from project X won't create a conflict with someone else adding a target on project Y, which where previously the same .xcodeproj (not exactly sure this is a conflict case, but there definitely are some).

Now with Xcode4 you can create a workspace and add all your projects there. Only for documentation purpose :)

To view and modify subproject implementation files, you should add the sub projects directly into the main project.
1 step - Drag and drop the .xcode project files to main project.
2 step - Go to main project TARGETS - > Build Phases. Add subproject target in Target Dependencies. You can also add binary files in Link Binary With Libraries.
3 step - Add subproject source path to main projects header search path.
Go to main project - > Build Settings - > Header Search Paths (e.g $(SRCROOT)/../CoconutKit-master/CoconutKit/Sources )

An Xcode project can have any number of build targets within it, and you can arbitrarily group source files into folders. What makes you think that multiple projects are necessary?

Related

Minimum of MyProject Files needed

I am writing a very basic library in VB.NET
The library just contains classes and modules.
Now in built output I see this files
Application.Designer.vb
Application.myapp
AssemblyInfo.vb
Resources.Designer.vb
Resources.resx
Settings.Designer.vb
Settings.settings
Since I've seen other libraries with only AssemblyInfo.vb file, I was wondering if I can delete the rest.
What is the minimum of files I need here for the lib to work correctly, since I don't have any ressource or setting?
All the files you listed are necessary for a vb.net library project. And these files are generated (in My Project folder) when the project created not the build output files. So you need to keep all the files you listed in order to develop and build your project locally.
And for the files of build output, you can add these files in .gitignore.
When you create a project in VS, you select a predefined template that dictates what gets created. People often become accustomed to seeing the superfluous objects that a given template creates and assume that those objects are mandatory and must be there, However, much of it is not needed.
There is also the Empty Project template (the exact name of this template varies depending on the VS version used).
In VS2017, selection of the template would look like this:
This is a bare-bones project and the Solution Explorer will look like this:
As you can see, there are no pre-loaded references. You will need to add them yourself. About the only thing defined in this template is that you are using the VB language; This project starts out as a WinForm type, so go to the Project Properties->Application tab and change the "Application type" to "Class Library" since you want to create a library.
You may find it useful to start with an Empty Project and add the stuff you normally use and then export the project as new template (in VS2017: Project Menu->Export Template). For more on creating termplates, see: Creating Project and Item Templates
Edit: I just realized that I did not answer your real question about deleting the unused items. I just did a test case and deleted the items under MyProject. I received an error on deletion, but doing a clean/rebuild allowed me to proceed without issues. I would recommend that you backup the project before attempting this on an existing project, but I saw no long term issues in deleting unneeded objects from MyProject.

Build Multiple iOS Apps out of a Framework

I have a project where I need to build some apps out of one Basic App.
For "Sub-Apps" it changes the API-Credentials, Fonts, Sizes, Colors and some features of the App.
So I changed my App that I can easily add features, change colors, ... by changing simple String constants to build new Apps faster.
I thought that the best solution would be to add multiple Targets to this XCode Project and set the individual Settings of the App with Conditional Compiler flags
#ifdef AppTarget1
qr_reader = YES;
#endif
But the Problem is, that in future will be available multiple versions of the Framework. So when updating an App based on a old Framework we always had to do the adjustments to work with the new Version of the framework (if any) and we've no control over the Framework Versions, ect.
One goal is also to allow our Developers with a Simple Podfile build new Apps easily.
So the next idea was to create a Framework Project, what then is included with CocoaPods in our Main Apps. I followed this tutorial: http://chariotsolutions.com/blog/post/using-cocoapods-to-manage-private-libraries/
In the MainApp I included the Framework, the MainApp-AppDelegate Class is a Subclass of the Framework-AppDelegate Class.
#interface MainApp_AppDelegate : FrameworkAppDelegate
The Method where I set all the App-Based Settings I overwrite in the MainApp_AppDelegate.
#implementation MainApp_AppDelegate
-(void)initSettings {
qr_reader = YES;
}
#end
It worked like a charm, but one Problem I've with images. The AppFramework contains Image training.png and image y.png.
In the Main App xyz I decide that the Image training.png looks not good for this App, so I want to change only that (y.png I want the version included in the Framework). I put the x.png into the Main App Ressources Folder, but after compiling and Running there I see the Image included in the AppFramework Project.
Are there any ways to change that behaviour or better ways to create a Framework?
What is happening is Cocoapods copies its resources in the final .app bundle after your app is done copying his. So your training.jpg gets overwritten by your framework's.
Build phases order
As #masam said, you need to reorder the build phases of your project in order to copy your app's resources after Cocoapods' resources.
(Notice how "Copy Bundle Resources" is now under "Copy Pods Resources" in the list)
Force resources copy
Unfortunately, this will not be sufficient, as Xcode's build system is (tries to be?) smart and will not copy (or recompile in the case of a source file) a target which is "up-to-date". For a static resource like an image, being up-to-date means that the target path (in the final .app bundle) is newer than the source path (in you Xcode project).
So if you try to run your app now, you will notice no change. Xcode won't copy the training.jpg as it is already present and newer in the .app.
You will need to trick Xcode into thinking that the resources in the .app are outdated and needs to be updated. To do this, add a new "Run Script Build Phase" between "Copy Pods Resources" and "Copy Bundle Resources":
The script should set the modification date of the resources to an earlier date, to force Xcode to copy your app's resources. touch does the job:
find ${TARGET_BUILD_DIR} -name 'training.jpg' -exec touch -ct $(date -v-1d "+%Y%m%d%H%M.%S") {} \;
We use date -v-1d "+%Y%m%d%H%M.%S" to set the resource's modification date to yesterday.
Xcode will now overwrite the framework's image with the app's one.
Manage the targets resources
Again, as #masam said, don't forget to add the resource only to correct targets.
eg.
Here, the app image will be used in DummyApp, but DummyApp2 will use the framework image.
Conclusion
tl;dr: Avoid this if possible.
For a newcomer on your project, this is impossible at first glance to know why some targets build with one file and not the other;
Depending on the kind of resources of the framework you want to override, you will probably need to maintain the "Reset Resources Modification Time" script (probably by making find more inclusive, eg. find ${TARGET_BUILD_DIR} -name '*.png');
More of a subjective opinion: I'd recommend against hiding resources from the framework with your owns.
On the one-target-per-app-flavor thingy:
Remember that each modification you make on one target's Build Phases will NOT impact other targets Build Phases. You'll need to edit every targets individually. Hence my previous don't do it if you can avoid it.
I perfectly understand the need to have multiple targets to build multiples apps based on the same codebase, but Xcode is horribly bad at managing a large number of targets. Take it from a guy currently working on an fairly large app (1k+ files, and a lot of dependencies) with 65 different targets: this is a nightmare.
The .pbxproj will basically grow in factor of your number of targets (25MB in my case), and you'll get the beach ball each time a project modification in done in Xcode. And as each target is managed independently, each time you need to eg. add/remove a compile flag, you will need to update each target, one. by. one. (or you will edit the .pbxproj "by hand" with sed/awk/whatever, which is faster, but risky... but fun :)).
Oh... and did I mention merge conflicts?
This might be due to a certain order in your build phases (Project -> Build Phases). Default, it will copy the bundle resources first and then copy Pods resources (overwriting the resources you had in your main application).
You could change the order of "Copy Pods Resources" to an earlier phase by dragging it to above "Copy Bundle Resources".
You also have to verify that the image resource included in your main project, has a correct target membership, by clicking on the image resource -> file inspector -> target membership. It should be checked for the target you are compiling.
duplicate your targets !?
The last apps I build by this way were using a different bundle identifier for each target.
Then just have a test to you bundle ID to make your different settings programmatically.
NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier];

One Xcode project using another without making a static library

I just banged my head for a while and figured out a solution, but I want to make sure that I'm doing things right and that I actually know what I'm doing (I'm pretty sure I never know what I'm doing :)
I have two projects that I've been working on, each offering different functionality. I want one project (A) to be able to use the functionality of the other (B). I tried going about it by creating a workspace and putting both projects into it, but I couldn't "see" project B's files from project A (autocomplete after #import did work, but it gave a compiler error). So I tried adding it as a "sub-project" and found the same. I figured this would be easy, but guess not.
What I ended up doing was creating a new project (C) as a "Cocoa Touch Static Library" project, and put my files from Project B into it. I built it.
I then went back to project A and added project C into it as a sub-project.
Then I added the path on the filesystem of project C into the User Header Search Paths setting under Build Settings of project A.
Then I added the .a file from Project C into the Link Binary with Libraries section of Project A.
Then it worked.
But honestly I have no idea what the meaning of a static library is.
Is all this necessary? Or is there an easier way to just integrate two projects (without me having to copy the files from one project to another)?
Thanks in advance!
Jon
You were on the right track with workspaces. What I do is have three projects in the workspace. One with no targets just to hold the generic classes. A second for my iOS target Project. And a third for mac. Keep the original files in the one with no target, then drag the files to the other two projects that creates references, so when you edit one it changes all three.

Merging Xcode project files

There are often conflicts in the Xcode project file (Project.xcodeproj/project.pbxproj) when merging branches (I'm using git). Sometimes it's easy, but at times I end up with a corrupt project file and have to revert. In the worst case I have to fix up the project file manually in a second commit (which can be squashed with the previous) by dragging in files etc.
Does anyone have tips for how to handle merge conflicts in big and complex files like the Xcode project file?
EDIT-- Some related questions:
Git and pbxproj
Should I merge .pbxproj files with git using merge=union?
RESOURCES:
http://www.alphaworks.ibm.com/tech/xmldiffmerge
http://www2.informatik.hu-berlin.de/~obecker/XSLT/#merge
http://tdm.berlios.de/3dm/doc/thesis.pdf
http://www.cs.hut.fi/~ctl/3dm/
http://el4j.svn.sourceforge.net/viewvc/el4j/trunk/el4j/framework/modules/xml_merge/
Break your projects up into smaller, more logical libraries/packages. Massive projects are regularly the sign of a bad design, like the object that does way too much or is way too large.
Design for easy rebuilding -- this also helps if you're writing programs which must be built by multiple tools or IDEs. Many of my 'projects' can be reconstructed by adding one directory.
Remove extraneous build phases. Example: I've removed the "Copy Headers" build phase from all projects. Explicitly include the specific files via the include directive.
Use xcconfig files wherever possible. This also reduces the number of changes you must make when updating your builds. xcconfig files define a collection of build settings, and support #include. Of course, you then delete the (majority of) user defined settings from each project and target when you define the xcconfig to use.
For target dependencies: create targets which perform logical operations, rather than physical operations. This is usually a shell script target or aggregate target. For example: "build dependencies", "run all unit tests", "build all", "clean all". then you do not have to maintain every dependency change every step of a way - it's like using references.
Define a common "Source Tree" for your code, and a second for 3rd party sources.
There are external build tools available. This may be an option for you (at least, for some of your targets).
At this point, a xcodeproj will be much simpler. It will require fewer changes, and be very easy to reconstruct. You can go much further with these concepts to further reduce the complexity of your projects and builds.
You might want to try https://github.com/simonwagner/mergepbx/
It is a script that will help you to merge Xcode project files correctly. Note that it is still alpha.
Disclaimer: I am the author of mergepbx.
The best way I have found is to instruct Git to treat the .pbxproj file as a binary. This prevents messy merges.
Add this to your .gitatributes file:
*.pbxproj -crlf -diff -merge
To compare two Xcode projects open open FileMerge (open xcode and select Xcode (from the manu pane) --> Open developer tools --> FileMerge).
now click "left" button and open xcode project main directory.
click "right" button and open xcode project main directory to compare.
Now click "merge" button!
Thats it!
Another option to consider which may help to reduce the number of times you experience the problem. To explain, I'll call the branch that team members' branches come from the "develop" branch.
Have a convention in your team that when the project file is modified, the changes (along with any other changes required to ensure the build integrity) are committed in a separate commit. That commit is then cherry picked onto the develop branch. Other team members who plan to modify the project file in their branch can then either cherry pick into their branch or rebase their branch on the latest develop. This approach requires communication across the team and some discipline. As I said, it won't always be possible; on some projects it might help a lot and on some projects it might not.

Best practices when importing class files in xcode

I'm working with xcode and I have classes associated with other projects that I want to be included in new projects. I realize that the #import will do the job technically (although what should i do if it's out of the project root folder). But what do I do if I want to include the class "properly" --basically so i can double click and edit out of the main project window where you can see all your files and such.
I guess I'm just looking for the best and/or proper way to include/import (into the project) .h and .m files that I've already created outside of the current project I'm working on. Taking into consideration that I may want to modify the class from the original without subclassing. Hopefully this makes sense.
Thanks,
Nick
Xcode project file organization doesn't reflect the data files on disk. Files can be added to a project from anywhere in the file system. When you add the files, choosing not to copy the files to the current project's directory means that the original files are used. Selecting one of these files in Xcode for editing will alter the original file in that other project. When returning to that other project, Xcode will use the edited files in any further work.
This type of use can be quite handy while working on multiple projects with some shared code. Yet, it can also cause headaches for a versioning system.
Might be worth thinking about how to make the classes into a private framework - then you can import that as another dependency each time. Alternatively you could use a separate version control system location to store the shared classes and just check that out into the project folder.