DevelopingForiOS
This page covers the details of how to make the transition from programming for Mac OS X to developing for iOS, the operating system used on the iPhone and iPad.
See also:
Important note: I started writing this page when iOS 4 was current. Unfortunately I have not been able to keep up with all the changes Apple made over the years, so a lot of stuff on this page is probably horribly out of date. My advice: Take everything you read here with a grain of salt.
Resources
Administration Documentation
These documents help with understanding the somewhat daunting task of managing the various public/private keys, certificates and provisioning profiles:
- App Development Overview [1]
- iOS Team Administration Guide [2] (especially section "Preparing the Development Team")
- Tools Workflow Guide for iOS [3] (probably not very useful, I just mention this here for completeness sake)
- Technical Note TN2250 [4]: Understanding and Resolving Code Signing Issues
General Developer Documentation
Once you get past the initial administrative hurdles, you will be interested in the following developer-centric documentation. If you want to get going quickly, you should soon direct your reading to View and View Controller Programming topics in the next section.
- iOS Reference Library [5]
- iOS Development Guide [6]: A high-level overview of how to do things in Xcode. A good starting document (the HelloWorld example doesn't really work, though).
- iOS Application Programming Guide [7]
- iOS Human Interface Guidelines [8]
- Foundation Framework Reference [9]
- UIKit Framework Reference [10]
- UIKit Function Reference [11]
View and View Controller Programming
Views and View Controllers are one of the most fundamental concepts of an iOS app, so eventually you will get to know everything about them. Whether you like it or not :-)
- View Controller Programming Guide for iOS [12]
- View Programming Guide iOS [13]
- Table View Programming Guide iOS [14]
Glossary
Development cycle
- Development Certificate
- Identifies an iOS application developer, Apple therefore requires that a developer may have only one active development certificate. The certificate is issued by Apple after a CSR is submitted to the iOS Provisioning Portal. Xcode uses development certificates to sign application binaries that are distributed to development iOS devices. The development certificate is also used to sign a provisioning profile and associate a developer to a registered device.
- Distribution Certificate
- Xcode uses distribution certificates to sign application binaries that are distributed to non-developer devices. Unlike development certificates, where each developer has his or her own certificate, a team can have only one distribution certificate. Distribution certificates are issued by Apple after a CSR is submitted to the iOS Provisioning Portal.
- Code Signing Identity
- The combination of a signing certificate and the corresponding private key is called a code signing identity. The signing certificate can be a development certificate or a distribution certificate.
- Development Provisioning Profile
- A Development Provisioning Profile (unofficially called DPP in this glossary entry) is installed on a development iOS device to authorize an app that is still under development to run on that device: iOS refuses to launch the app unless it finds a DPP that says "this app, signed by that development certificate, is allowed to run on this device". A DPP is not tied to only a single app, development certificate or device, it is a collection of all of these. A DPP authorizes a specific set of apps to run, it authorizes a specific list of devices to run those apps, and it authorizes a specific list of development certificates to sign those apps. In addition to being installed on an iOS device, the DPP must be installed on development computers also: The profile authorizes Xcode to sign the app. A DPP is represented by a file, e.g.
~/Library/MobileDevice/ProvisioningProfiles/foo.mobileprovision
. - Distribution Provisioning Profile
- Similar to Development Provisioning Profiles in that they authorize an app to run on an iOS device. However, only non-development devices can be authorized, and apps must be signed with a distribution certificate. There are two kinds of distribution provisioning profiles: 1) Ad-hoc provisioning profiles, which are used by testers and other users to install and test application that have not been published to the App store. 2) App Store distribution provisioning profiles, which are used, as the name says, to publish apps to the App store. The type of a distribution provisioning profile is determined at the time it is created on the iOS Provisioning Portal, by selecting the appropriate distribution method.
- Bundle ID
- A bundle ID is a string that uniquely identifies an app in all sorts of contexts. It should be written in reverse-DNS format. For instance, I use
ch.herzbube.littlego
as the bundle ID for my Little Go app. The bundle ID is specified using theCFBundleIdentifier
key in the app'sInfo.plist
file. - App ID, application ID, iOS application ID
- A string that identifies an iOS application or a set of iOS applications from one vendor. An app ID consists of a bundle seed ID, followed by a dot character ("."), and a bundle ID search string. This is an example app ID
A1B2C3D4E5.*
, and this is anotherGFWOTNXFIY.com.mycompany.myapp
. There are two types of app IDs: wildcard app IDs (the first example) that refer to multiple applications, and explicit app IDs (the second example) that refer to a single application. - Bundle seed ID
- A universally unique 10 character string generated by Apple. Can be used to share keychain data such as passwords between applications that have the same app ID.
- iOS runtime environment
- There are 2 of these: The simulation environment and the device environment. A build is targetted at one of these environments through the SDK that it uses (the SDK belongs to an SDK family that matches the environment)
- Runtime environment
- In a different part of the docs I have seen this term (without the "iOS" prefix) to refer to the version of iOS that is targetted.
- SDK family
- A collection of SDKs that target an iOS runtime environment (simulation or device). Obviously, there are as many SDK families as there are runtime environments.
- Architecture
- Devices currently use two architectures:
armv6
andarmv7
. A build that targets a device can be configured for optimization in regard to the device's architecture: 1) Optimized: Separate code optimized for each architecture, resulting in a larger executable. 2) Standard: Common code usable on all architectures, resulting in a smaller but not very optimized executable. - Device family
- Currently there are 2 of these: iPhone and iPad. Each family may contain more than 1 device (e.g. the iPhone family consists of the iPhone and iPod devices). A build is targetted at one device family.
- UDID
- Unique Device ID. World-wide unique device identifier consisting of 40 characters. The UDID can be used to add a device to a Provisioning Profile on the iOS Provisioning Portal.
View programming
- Status bar
- The bar at the top of the screen which displays the time and other status information on the iOS device
- Navigation bar
- A bar at the top of the screen which is used to navigate in a hierarchical set of data. A tab bar usually has a title that indicates the location within the hierarchy, some sort of "back" button to navigate back to the previous level of the hierarchy, and it may also contain optional controls that relate to the content of the current view. A navigation bar is displayed and managed by
UINavigationController
- Navigation toolbar
- A bar at the bottom of the screen which is optionally displayed by
UINavigationController
and may contain arbitrary custom buttons. - Tab bar
- A bar at the bottom of the screen used to select different modes of presentation in an application. A tab bar contains tab bar items. A tab bar is displayed and managed by
UITabBarController
- Toolbar
- A bar usually at the top of the screen which contains a set of toolbar items that are used to trigger different actions that relate to the data displayed in the view. A toolbar is managed by a custom view controller
Xcode and iOS SDKs
- Download the latest version of Xcode and iOS SDK from the iOS Dev Center. You may also get older versions of Xcode here that support older versions of Mac OS X (if you don't have the latest & greatest version of the OS).
- To get an older version of of an iOS SDK installed together with a newer version of Xcode (e.g. iOS SDK 4.3 with Xcode 4.2): Launch Xcode 4, then go to Preferences > Downloads section > Components tab > Click "Install" next to the "iOS x.y simulator" entry.
- stackoverflow.com instructions how to get the newer iOS 5.1 SDK installed with the older Xcode 4.2.
iOS Developer Program
Overview
- Go to http://developer.apple.com/
- Find the link that lets you join the "iOS Developer Program".
- This costs an outrageous USD 99 per year!!!
- But it's required if you want to run your application on a real iPhone (not just in a simulator) and distribute it via App Store
- If the renewal fee is not paid every year, the License Agreement (see below) will run out and Apple may cease distribution of applications and/or revoke certificates.
- Certificate revocation is unlikely to happen, as it would cause installed applications to become inoperable - I don't think Apple will risk the wrath of their customers just because the developer failed to pay his annual fee
- The "cease to distribute" thing will probably happen as it has no impact on people who have already downloaded applications. Schedule 1, section 1.4 reiterates the matter and specifies that Apple will continue to distribute at most 30 days after the license agreement has run out.
Note on names:
- If your name contains any special characters, I advise against using them!!!
- Because I specified "Näf", the activation of my account failed at first (at least I assume that was the reason) and I had to write to Apple a special explanation before activation was granted
- After the account was activated, I noticed that the name associated with my profile is now "Naf", i.e. no umlaut character. This is very annoying, as the correct replacement of the umlaut character in my name is "Naef"
- The name has to be specified again when a developer certificate is requested: Now I wonder whether I should use "Naf" (would match the profile, but I hate this), "Näf" (the correct name, but I fear this will take the wrong turn again), or "Naef" (correct replacement of the offending umlaut, but doesn't match either my profile or my real name). Update: I have decided to with "Näf". This is consistent, and I
- This is all really ridiculous and I wonder how my apps will end up being presented in the App store
Quotes from the "iOS Developer Program License Agreement"
Quotes come from version 2010-09-09 of the License Agreement.
- Section "Purpose"
- Distribution of free (no charge) Applications that do not make use of the In App Purchase API will be subject to the distribution terms contained in Schedule 1 to this Agreement.
- If You would like to distribute Applications for which You will charge a fee or would like to use the In App Purchase API in free Applications, You must enter into a separate agreement with Apple (“Schedule 2”).
- Section 2.2
- You acknowledge that by installing any pre-release Apple Software or using any pre-release services on Your Authorized Test Devices, these Devices may be “locked” into testing mode and may not be capable of being restored to their original condition.
- Section 3.3
- Interpreted code may only be used in an Application if all scripts, code and interpreters are packaged in the Application and not downloaded. The only exception to the foregoing is scripts and code downloaded and run by Apple's built-in WebKit framework.
- Applications must comply with the Human Interface Guidelines and other Documentation provided by Apple
- If Your Application includes any FOSS, You agree to comply with all applicable FOSS licensing terms. You also agree not to use any FOSS in the development of Your Application in such a way that would cause the non-FOSS portions of the Apple Software to be subject to any FOSS licensing terms or obligations.
- Section 5
- All Applications must be signed with an Apple-issued certificate in order to be installed on Registered Devices.
- You further represent and warrant to Apple that the licensing terms governing Your Application, or governing any third party code or FOSS included in Your Application, will be consistent with and not conflict with the digital signing or content protection aspects of the Program or any of the terms, conditions or requirements of the Program or this Agreement.
- Section 8
- You understand and agree that Apple may cease distribution of Your Licensed Application(s) and/or Licensed Application Information or revoke the digital certificate of any of Your Applications at any time. By way of example only, Apple might choose to do this if at any time: [...] (k) You fail to renew this Agreement and pay the applicable renewal fee
- Section 10.1
- You agree that [...] the terms and conditions of Schedule 2 (available separately to cover distribution of paid-for Licensed Applications via the App Store) will be deemed "Apple Confidential Information" [...]
- Notwithstanding the foregoing, Apple Confidential Information will not include: [...] (v) any FOSS included in the Apple Software and accompanied by licensing terms that do not impose confidentiality obligations on the use or disclosure of such FOSS.
- Section 3.1 of Schedule 1
- The parties acknowledge and agree that Apple shall not acquire any ownership interest in or to any of the Licensed Applications or Licensed Applications Information, and title, risk of loss,responsibility for, and control over the Licensed Applications shall, at all times, remain with You.
Notes on the "iOS Developer Program License Agreement"
Notes refer to version 2010-09-09 of the License Agreement.
- I read chapters 1-12 and the "Schedule 1" appendix pretty thoroughly
- I did not read chapters 13-15 (NO WARRANTY, LIMITATION OF LIABILITY and General Legal Terms)
- I also did not read sections, chapters and attachments that refer to features that I am not going to use at the moment
- I investigated all occurrences of the term "FOSS" and did not find anything "alarming"
- Except for the clause that forbids downloaded interpreted code (somewhere in section 3.3), there are no other requirements for specific programming languages. I was on the lookout for such requirements because I had heard that only Obj-C and C++ were allowed. This must have been in an earlier version of the agreement, though.
Licensing
Introduction
It is very unfortunate that this section exists, because I would rather concentrate on developing code than spend my time on licensing matters. Unfortunately, Apple's approach of forcing people to distribute their software over the App Store has implications on the license that you can choose for your own software. Also, if you want to integrate third-party software in your application, there are restrictions based on the license under which the other software has been published.
References
- OSI approved licenses
- GPL v2
- GPL v3
- Apache License 2.0
- BSD License (links to opensource.org, I have not found any other authorative repository)
Which license to choose for your own software
The obvious question is: Can I use the GPL?
- http://stackoverflow.com/questions/762498/iphone-and-gpl
- Not very helpful, but it's a starter and it provides a link to the Colloquy project
- A quick search on fsf.org for the position of the FSF in regard to the iPhone (or iPad) revealed that they are against the device. The articles I found, though, are over 2 years old.
- http://diveintomark.org/archives/2008/03/07/iphone-gpl
- One commenter says that it is enough to provide links that point to the source code (hosted e.g. on your own site) in the application's blurb on the App Store. "[...] As long as the code is available to the users of the software then the GPL is satisfied.". Another commenter disagrees with this: "The FSF's position is that every distributor must provide source code for GPL binaries they distribute. See here: http://www.linux.com/feature/55285." Yet another commenter thinks the first poster was right: "[...] see section 6d of GPLv3 you can distribute the source from a different server as long as you specify it and it stays available.". The second commenter then refutes this by saying "I don’t think 6d is a get-out for Apple. If you’re a distributing licensee, you have a responsibility to provide a source for the source. The last sentence says it all: “Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.” Apple can’t make that guarantee if the source code is hosted on the original developer’s server, they have to host it themselves."
- A very good article is referred to somewhere in all this discussion, and although it's about derivative Linux distributions, a subject seemingly quite remote to the discussion of iPhone applications, it contains valuable reasoning from one of the FSF guys: "We think it's pretty clear," says David Turner, GPL compliance engineer at the FSF. "One problem with allowing people to skip out on source code distribution is that there's nothing that requires the upstream distributor to continue to offer source code. If they stop doing so, the source could become totally unavailable. Or, more commonly, the upstream distributor will upgrade the version of the source code available, leaving downstream distributors totally out of sync. In order to fix bugs, users need to get source code exactly corresponding to the binaries they have available."
- What about putting a link in your application that leads the user to the hosted source code? Looking at the reasoning above, this is just as bad as providing a link into the application's blurb on the App Store.
- One commenter quotes a "noncommercial" clause from the license (v2 or v3?) that may apply for programs that can be downloaded for free from the App Store. The clause says "c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)". This is another argument in favor of "just include a link and it's ok". The main question, of course, is whether Apple's distribution of free applications is considered "noncommercial". The other question, which is minor, is whether Apple received an offer from upstream to provide the source code. Of course :-) I would be willing to make this offer to Apple!
- One commenter proposes to "[...] include the source in the signed application, something I’ve seen in windows installers of GPLed software, assuming there’s a way to get it off the iPhone." This is probably the best of all the proposed solutions, and although it may be impractical for large projects with a large code base, it may just prove to be the legal escape required to be able to use the GPL
- Some commenters remark on whether the license is satisfied if you can get the source code, but are then unable to use it. Problems such as "how to read the source code once it is on the iPhone", or "how to get the source code off the iPhone so that it can be compiled", or even the complaint that "you need to buy a $99 dev license to be able to run the self-compiled application on a real device". I don't think this discussion is relevant, though, otherwise you would have to discuss other issues as well such as "I need to pay for getting Internet access".
- At some point the spirit of the GPL, as opposed to its letter, is brought up, which of course opens up the field for ideological discourse (read "flame wars")
How have other projects resolved the GPL issue?
- Pointers to other projects
- geoffeg.org: A reassuring :-) article from someone who has published GPL (v2) software for the iPhone and who, after spending much thought on licensing, apparently has no ideological or other problems with the GPL
- Colloquy Mobile
- This software is OSS, but they charge money for it
- They talk about getting the source code in their FAQ
- Even from the FAQ it is unclear, however, which license they use (some references found with googling say that it's BSD)
Other licenses
- The most common OSS licenses that come to mind are the Apache License, and the BSD License
- Apache License 2.0
- Interestingly, there seems to be almost no discussion at all as to whether the Apache License is suitable for iPhone/iPad development
- On reading the license, it is pretty clear why: The license is not very long and quite easy to understand, i.e. no discussion is really needed
- The "Redistribution" clause clearly places no responsibility on Apple to distribute anything except the license itself together with the binary
- Since I will make the license available from within the program, the Apache License is clearly suitable for apps distributed via Apple's App Store
- BSD License
- This license consists of only 3 clauses and is really easy to understand in its entirety
- Since I will make the license available from within the program, the BSD License is clearly suitable for apps distributed via Apple's App Store
Conclusion
- As always with the GPL, the issue is unclear
- From the ideological and die-hard point of view of the FSF, the GPL is not suitable for iPhone/iPad apps
- There are, however, some arguments that in my view would allow to choose the GPL as license for iPhone/iPad apps
- Since I wrote the software I own the copyright and can choose my own licensing. This allows me to state exceptions to the GPL that will make it legal to distribute the software via App Store. The question is, how much legal-speak is necessary for such a statement?
- Final verdict: I prefer not to stand in ideological and possibly legal fire if there are alternatives, therefore I am going to use a different license than the GPL
- I decide to use the Apache License because it works and is a little bit less liberal than the BSD license
Which software can you use in your applications
No GPL software is possible. The famous cases are GNU Go (fsf.org article from 2010) and VLC (Google search). To understand the FSF's stance on the issue, this fsf.org article explains the details of the conflict between the GPL and Apple's terms of service.
LGPL is heavily debated. Unlike GNU Go and the GPL, the FSF has never made an official case against any LGPL'ed piece of software being distributed over the App Store. Taking into account that the FSF is vehemently against the App Store (here and here), I believe it is safe to assume that there is no strong legal case against using LGPL'ed 3rd party software in an application. In order to remain in good standing with the authors of such software, I would definitely recommend to discuss the subject with them, in the hope of getting their approval.
The Apache and BSD licenses are, as far as I know, no problem and 3rd party software published under these licenses is perfectly possible. Usage may need to be documented.
Getting a device ready to run applications
Getting a Developer Certificate
Before you can get a Developer Certificate from Apple, you must enroll in the "iOS Developer Program". Once you have your account, do the following to get a certificate:
- Generate a Certificate Signing Request (CSR) with a public key
- Launch the application "Keychain Access"
- Start the generation process
- If you already have a private key that you want to use for issuing a CSR, you can right-click on that key and select "Request a Certificate from a Certificate Authority"
- If you need a new private key, choose from the menu: Keychain Access > Certificate Assistant > Request a Certificate from a Certificate Authority. Using the Key Chain Assistant automatically generates a new public/private key pair
- I suggest making a backup copy of the private key, because the certificates you get from Apple are worthless without this key!
- In the "Certificate Information" window, enter or select the following information:
- In the "User Email Address" field, enter your email address
- In the "Common Name" field, enter your name. Note: Special characters are encoded as UTF-8.
- In the Request is group, select the "Saved to disk" option
- Click Continue
- Select the destination where to save the CSR file
- Submit the CSR through the iOS Provisioning Portal
- Log in
- Select the "Certificates" item in the navigation column on the left
- Select the "Development" tab
- Click the "Choose file" button and navigate to the CSR file
- Click the "Submit" button
- Wait until the CSR has been processed. This shouldn't take too long, so recheck the portal after a minute or two
- Download the issued certificate and import it to your keychain
- Certificate attributes
- The name begins with "iPhone Developer"
- The certificate is valid for 1 year
- Only one Developer Certificate per person
- Purpose of the certificate
- Sign a Provisioning Profile
Getting a Distribution Certificate
Before you can get a Distribution Certificate from Apple, you must enroll in the "iOS Developer Program". Once you have your account, do the following to get a certificate:
- For the basic procedure, see above under "Getting a Developer Certificate"
- You probably want to re-use the same private key for generating the CSRs for your Distribution Certificate
- On the iOS Provisioning Portal, you submit the CSR under "Certificates > Distribution" instead of "Certificates > Development"
Provisioning a device for development
Before you can provision a device for development, you need to get a Developer Certificate and a Distribution Certificate from Apple. Once you have your certificates, do the following to provision a device:
- Launch Xcode
- Open the "Xcode Organizer" (Window -> Organizer)
- In the "Development" group, select "Provisioning Profiles"
- Select the "Automatic Device Provisioning" option
- Plug in the device
- In the "Devices" group, select your device and click "Use for Development"
- In the dialog that appears, enter your iOS Developer Program credentials
- Xcode now logs in to the iOS Provisioning Portal and adds the new device to it
- Xcode also adds a provisioning profile called "Team Provisioning Profile: *" to your device.
- This profile is for development only
- This provisioning profile is shared among the members of your team who provision their devices automatically
- On the iOS Provisioning Portal, select the "Provisioning" item in the navigation column on the left
- Select the "Development" tab to view existing Development Provisioning Profiles
- If you haven't got a Developer Certificate yet, Xcode will offer to request one in your behalf. You must click "Submit Request" here.
- If you haven't got a Distribution Certificate yet, Xcode will offer to request one in your behalf. You must click "Submit Request" here.
- Xcode then goes on to install the provisioning profile to your device. I experienced a moment of unease when Xcode seemed to be stuck in an infinite loop during the "Installing team provisioning profile" phase. Following the advice found here I simply unplugged the iPhone, reconnected, and got the expected message from Xcode about "not having debugging information". I let it collect the data (I had to enter admin credentials) and after a while everything seemed to work.
Ad Hoc Distribution of an Application
Useful links:
- http://stackoverflow.com/questions/40154/how-do-you-beta-test-an-iphone-app
- Technical Note TN2250 [4]
Make sure you have obtained a Distribution Certificate before continuing any further.
- Collect UDIDs of all devices that should be able to run the application
- The easiest way probably is to get people to install the free app Ad Hoc Helper. The app creates an email containing the UDID and other information about the device. The user can edit the message text and then send the email to you.
- A device's UDID can also be determined manually by connecting the device to iTunes or Xcode
- In iTunes, select the device and navigate to the "Summary" tab. Click on the "Serial Number" label to reveal the UDID
- In Xcode, open the "Organizer" window, navigate to the "Summary" tab where the UDID is displayed
- When you have collected all UDIDs, register them on the iOS Provisioning Portal
- Select the "Devices" item in the navigation column on the left
- Select the "Manage" tab
- Add the devices
- Note: Only up to 100 devices can be added per year
- Obtain an "Ad Hoc Distribution Provisioning Profile"
- Log in to the iOS Provisioning Portal
- Select the "Provisioning" item in the navigation column on the left
- Select the "Distribution" tab
- Click the "New Profile" button
- Select the "Ad Hoc" radio button
- Enter a profile name (e.g. "Beta test profile for the Little Go app")
- Select the appropriate Distribution Certificate (if you have more than one)
- Select an appropriate App ID (e.g. the wild-card ID created by Xcode)
- Select the devices that should be able to run the application
- Click the "Submit" button
- Wait until the request has been processed. This shouldn't take too long, so recheck the portal after a few seconds
- Download the profile (results in a .mobileprovision file)
- Double-click the profile in the Finder; the file opens in Xcode, the profile now appears in the "Organizer" window on the "Provisioning Profiles" tab
- Configure the application for distribution
- Open the project in Xcode
- Open the "Info" window for the top-level item in the "Groups & Files" section on the left
- Select the "Configurations" tab, select the "Release" configuration and click the "Duplicate" button; name the new configuration "Distribute"
- Select the "Build" tab
- Select the new configuration "Distribute"
- Click the "Any iOS Device" pop-up menu below the "Code Signing Identity" field and select the iOS Distribution Certificate/Provisioning Profile pair you wish to sign and install the application with
- Open the "Info" window for the build target
- Select the "Properties" tab
- In the "Identifier" field, enter the Bundle Identifier portion of the App ID that was chosen to create the Distribution Provisioning Profile
- If you have used an explicit App ID you must enter the Bundle Identifier portion of the App ID
- If you have used a wildcard asterisk character in your App ID, replace the asterisk with whatever string you choose
- In the "Identifier" field, enter the Bundle Identifier portion of the App ID that was chosen to create the Distribution Provisioning Profile
- In the "Icon File" field, enter a reference to a 57x57 pixel icon that will be displayed on the iOS home screen
- Open the "Info" window for the build target
- Select the "Build" tab
- Fix the "Code Signing Entitlements" build setting so that it contains a relative path reference to the new Entitlements.plist
- Build the application for the iOS device (not the simulator) and the new "Distribution" configuration
- Distribute the application to provisioned devices
- The modern way
- In Xcode, select "Build and Archive" from the "Build" menu
- This will open the "Organizer" window and display the archived application build
- Select the build, then click the "Share..." button
- Select a code-signing identity (default should be OK), then click the "Distribute for Enterprise..." button
- A dialog opens that lets you fill in a few things about how you intend to distribute the build
- Most important is that the URL matches exactly the URL of the .ipa file as it is going to be available for download
- Example values
- URL = http://www.herzbube.ch/software/littlego/0.1/littlego.ipa
- Name = Little Go Beta Test
- You are now asked to specify a save location & name. This step creates both a .plist and an .ipa file, where the specified name serves as the base name for both files. Make sure to specify the same name as in the URL above.
- Upload the .plist, .ipa and .mobileprovision files to the server from where testers can download it
- Create an index.html at the download location that contains a modified version of the following:
- The modern way
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Little Go Beta Test</title> </head> <body> <ul> <li><a href="http://www.herzbube.ch/software/littlego/0.1/littlego.mobileprovision">Install Provisioning File</a></li> <li><a href="itms-services://?action=download-manifest&url=http://www.herzbube.ch/software/littlego/0.1/littlego.plist">Install Little Go application (version 0.1)</a></li> </ul> </body> </html>
- The old fashioned way
- Locate the build product (an .ipa file) in the Finder and create a .zip archive that contains both the .ipa and the .mobileprovision file
- Send the .zip archive to your testers
- The tester expands the archive and drags both files onto the iTunes
- The tester syncs the device, which installs the app
- The old fashioned way
Creating an App ID
Xcode automatically creates a wildcard App ID at some time during the provisioning process. This can be used for all of your applications unless they need one of the following things:
- Use external hardware accessories
- Use the "Apple Push Notification" service
- Use "In App Purchases"
To create an App ID:
- Go to the iOS Provisioning Portal
- In the "App IDs" section, on the "Manage" tab, select the button "New App ID"
- Enter the following information
- Description = Descriptive application name, e.g. "Test Application"
- Bundle Seed ID = Depending on your needs, either select the ID that has been automatically created by Xcode at some previous stage, or create a new ID
- Bundle Identifier (App ID Suffix) = A reverse-domain application ID, e.g.
ch.herzbube.testapp
- Click "Submit", the App ID should now appear in the list of your App IDs
- If you need to enable the application for the "Apple Push Notification" service, you must click "Configure" to do some more stuff
Renewal
Each year the membership in the iOS Developer Program expires. The developer and distribution certificates that were issued for the previous year's membership also expire and need to be replaced with new certificates when the membership is renewed.
- Automatic handling by Xcode, used when renewing for 2013
- As soon as the certificates have expired, go to Xcode's Organizer window, then under "Devices > Provisioning Profiles" click the button "Refresh" at the bottom right
- Xcode will detect that the certificates have expired and offer you to manage the process of acquiring new ones
- If you accept, Xcode creates two new RSA keys: One to request the developer certificate, and one to request the distribution certficate
- Xcode automatically creates and submits the CSR, then downloads the resulting certificates
- The certificates and the RSA keys are stored in the login keychain
- Manual handling, roughly tested in 2012
- Start by creating 2 new CSRs and submit them to the iOS Provisioning
- From here on, follow the same procedure as when you obtained your first developer and distribution certificates
- Usually you will want to reuse the same RSA key that you used to create the CSRs for the previous year's certificates. Note that you need the public key to generate the CSRs. If you only have the private key (e.g. because you migrated from another computer) Keychain Access will happily launch the Certificate Assistant application for you, but later on, after you have entered all the CSR data, the assistant will complain with an obscure message saying that it is missing a piece of data.
Provisioning Profiles are valid only for a relatively short period of time (3 months at the time of writing), so they need to be renewed from time to time.
- These are the steps to take if you let Xcode manage your Provisioning Profile
- Launch Xcode
- Open the "Xcode Organizer" (Window -> Organizer)
- In the "Development" group, select "Provisioning Profiles"
- Click the "Refresh" button at the top of the window (you may need to select the expired Provisioning Profile first)
- In the dialog that appears, enter your iOS Developer Program credentials
- Xcode now logs in to the iOS Provisioning Portal and automatically renews any Provisioning Profiles that have expired
- If you manage your Provisioning Profile manually
- Log in to the iOS Provisioning Portal
- Select the "Provisioning" item in the navigation column on the left
- Select the "Development" tab
- The column labelled "Status" should tell you which Provisioning Profiles have expired and which ones are still valid
- Expired profiles should have a "Renew" or "Modify" button in the column labelled "Action"
- Pick the expired Provisioning Profile you want to renew and click its action button
- On the edit screen you can now change a few properties of the profile, such as its name
- The submit button is active only if you change something (e.g. a slight modification to the name)
- After a change is submitted, the profile will be automatically renewed and available for download
- Once a profile has been renewed, Xcode will automatically download the profile if you click the "Refresh" button in the Organizer window
Importing public/private keypair into keychain on a different computer
You have backed up the public/private keypair you originally used to request your developer and distribution certificates from Apple. You are now on a different computer and want to import those keys into Keychain Access. You are in trouble.
The main problem is that Keychain Access will refuse to import the public key in PEM format. Without that key you will be unable to issue new CSRs, e.g. to generate a new developer or distribution certificate after you have renewed your iOS Developer Program subscription. Note that Keychain Access also complains when you import the private key (in PKCS#12 format, a .p12 file), but if you click away the error message the import has succeeded nonetheless.
The command line, once again, is your friend. To import both private and public keys, do this:
security import /path/to/private.key -k login.keychain -t priv security import /path/to/public.key -k login.keychain -t pub
(the -t
option is not really necessary, the utility will figure out by itself what type of data is in the file)
Publishing an app on the App Store
Create an App Store distribution provisioning profile
- Go to the iOS Provisioning Portal
- Select "Provisioning > Distribution > New Profile"
- Create the profile using the following characteristics
- Distribution method = App Store
- Profile name = <Application Name> App Store Distribution Profile (e.g. "Little Go App Store Distribution Profile")
- App ID = The appropriate application ID for the application being distributed. Can be a wildcard App ID. See Creating an App ID.
- Download the distribution provisioning profile
- Drag the distribution provisioning profile onto the Xcode dock icon
Create a new App Store Distribution build configuration
- In Xcode, select the project in the Navigator view on the left-hand side
- Select the project in the editor view in the middle of the screen (i.e. make sure that you do not have a target selected)
- Select the "Info" tab (yes, this is important!)
- From the menu, select "Editor > Add Configuration > Duplicate "Release" Configuration"
- Name the new configuration "Distribute_AppStore"
- Switch to the "Build Settings" tab and find the section titled "Code Signing"
- Below the new "Distribute_AppStore" configuration there is an "Any iOS SDK" setting: From the pop-up menu of this setting select the identity listed under the "App Store Distribution Profile"
- Select the application's main target
- Find the section "Build Options", then delete the "Validate Build Product" build setting for the "Release" configuration (and any other configuration where it may still be set)
Create a new Xcode scheme
- From the menu select "Product > Edit Scheme..."
- Select the scheme that performs the "Release" build
- Duplicate the scheme and name the duplicate "<Application Name> AppStore Distribution" (e.g. "Little Go AppStore Distribution"
- In the new AppStore scheme, set the build configuration for all actions, but especially for the Archive action, to "Distribute_AppStore"
- Make sure that the "Archive" action is disabled for the Debug and Release schemes
Add the app to iTunes Connect
- Log in to iTunes Connect
- Select "Add New App"
- If this is the first app of your developer account, you now need to enter a few things
- Important: These things cannot be changed anymore later on!
- Primary language: The language in which metadata will be uploaded. This language will be displayed in all AppStores worldwide, unless there are explicit localizations.
- Company name: The name that is displayed on the App Store in the upper left-hand corner of every product page.
- Enter the details for the new app
- App name
- SKU number = A unique UTF-8 alphanumeric identifier for the app, used to identify the app within the developer account (e.g. "littlego")
- Bundle ID = Select the wildcard AppID created by Xcode, then under "bundle ID suffix" enter the bundle ID used in the app's Info.plist (e.g. "ch.herzbube.littlego")
- Enter additional data
- Availability date (e.g. "now")
- Price tier (e.g. "free")
- Discount for Educational Institutions (e.g. false for free apps)
- Enter version information
- Version number = The exact version number (e.g. CFBundleShortVersionString) from the Info.plist
- Description = Text-only (e.g. no HTML) description of the app's purpose. 580 characters or less will display without the "more" button
- Primary, secondary and subcategories
- Keywords = Comma-separated list of keywords; may not be other app or company names
- Copyright = Copyright statement, without the copyright symbol (e.g. "2011 Patrick Näf"). It's probably best to use NSHumanReadableCopyright from the Info.plist
- Contact email = Non-public address used by Apple
- Support URL = Because this is required, and the App URL is not, I specify the application website here (e.g. http://www.herzbube.ch/littlego)
- App URL = Optional, should be the application website, but since I don't have a separate support page I don't use this field
- Review notes = Any notes useful for the review process
- Rating
Prepare a build that can be uploaded
- In Xcode, activate the "AppStore Distribution" scheme for the iOS device
- From the menu select "Product > Archive"
Upload the build
- In iTunes Connect, select the app, then click "Ready to Upload Binary"
- Step through the wizard and provide all necessary answers
- After finishing the wizard, you are returned to the app's version information screen. The app's status has now changed to "Waiting for Upload".
- In Xcode in the Organizer window, select the previously created archive
- Select "Validate..."
- Make sure that the appropriate code signing identity is selected (i.e. the identity for which you previously created "App Store Distribution Profile")
- If validation was successful, select "Submit..."
- The archive should now be uploaded
- In iTunes Connect, the app's status has now changed to "Upload Received"
Note that I have not tested the "Application Loader" app which is discussed at length in the iTunes Connect Developer Guide.
Steps to get a "Hello World" app on the iPhone
To get the application to run on the iPhone simulator:
- Download & install the "Xcode and iOS SDK" (4.2 at the time of writing) from the iOS Dev Center
- Run Xcode, then create a new project using the template "Window-Based Application"
- Select "Simulator" as the destination for the build
- Add a new class "MyView" by selecting "File->New File...->Objective-C class", then choosing "UIView" as the subclass
- Add the following snippets to
HelloWorldDelegate.m
#import "MyView.h" [...] // In application:didFinishLaunchingWithOptions: MyView *view = [[MyView alloc] initWithFrame:[window frame]]; [window addSubview:view]; [view release];
- Add the following new method to
MyView.m
- (void)drawRect:(CGRect) rect { NSString *hello = @"Hello, World!"; CGPoint location = CGPointMake(10, 20); UIFont *font = [UIFont systemFontOfSize:24.0]; [[UIColor blackColor] set]; [hello drawAtPoint:location withFont:font]; }
- Select "Build and Run" from the toolbar
- Enjoy :-)
To get the application to run on a real device:
- Enroll with the iOS Developer Program
- Get a Developer Certificate and a Distribution Certificate
- Create and submit a CSR (Certificate signing request) to the iOS Provisioning Portal
- Perform the steps required to provision a device for development
- In Xcode's toolbar, in the "Overview" button, select "Device" as the target environment
- Select "Build and Run" from the toolbar
- Enjoy even more :-)))
More stuff to research and write about
- Entitlements
- Encountered this here
- iOS provides access to special resources and capabilities through properties called entitlements
- File
Entitlement.plist
under Resources - If no special capabilities (push notifications, iCloud, etc.) are needed, and you do not do ad-hoc distribution, then you don't need an
Entitlements.plist
- To learn how to set up a device for development, see Managing Devices and Digital Identities
- Preprocessor macro TARGET_IPHONE_SIMULATOR conditionally compiles code to run only on the simulator or only on a device
- Preprocessor macro TARGET_OS_IPHONE conditionally compiles code to run only on iOS devices or only on Mac OS X
- Linking conditionally is also possible, see Editing Conditional Build Settings
- Build configurations
- iPhone/iPad builds: Create separate targets to get builds optimized for each device. Create a single target to get a build that works on both.
- Choice of SDK in regard to 1) simulator/device; 2) iOS version.
- Architecture optimization
- Setting "Base SDK" (e.g. iOS 4.2 SDK) and "Deployment Target" (e.g. iOS 4.0) results in a
MinimumOSVersion
entry in the application'sInfo.plist
. Details are here and here)
- When you build your application to run it on a device, Xcode signs it with a development certificate (also known as a code signing identity) stored on your keychain. See Preparing Your Mac for iOS Development. A project allows to configure the identity to use in its build settings
- Provisioning profile defines the application IDs that can be used. The ID is stored in the application's property
CFBundleIdentifier
- Application data can be erased by removing the application from the simulator or device's "Home screen". An application has its own file system, the one used in the simulator is stored here:
~/Library/Application Support/iOS Simulator/<sdk_version>/Applications/<app_name>
. To save/restore the filesystem on a device, use the Xcode->Window->Organizer tool. - Tests to perform
- Lock device
- Low-memory warning
- Using both the regular and the In-Call status bar (the latter is taller)
- How to perform gestures on the simulator
- How to "Measure and tune application performance"
- How to "Let others test the application"
- How to "Submit application to the App Store"
Application programming
Information in this section is taken from the "iOS Application Programming Guide" [7]
General concepts and notes
- Memory: Applications have virtual memory, but it is constrained to the available physical memory available because there is no swapping to disk. Applications may receive notifications that request that memory be freed
- Energy saving: The screen dims and then locks after a certain amount of time with no touch events. An application may disable this behaviour if absolutely needed (e.g. games with no touch input), but it is not generally recommended behaviour
- Multitasking: When an applications is not visible on the screen, the system suspends it after a short time. An application may request background execution time, but again this should only be done when required
- Sandbox: An application is installed in its own file system directory, which is called the Application Sandbox. The application is more or less free to manage its own directory space, but cannot access any files outside of the sandbox. The
Documents
sub-directory can be made available to the user on a desktop computer. Parts of the sandbox are backed up by iTunes. - Passwords and other secrets can be stored in keychain items
- An application can specify in its
Info.plist
any hardware features that it requires to run. The presence of hardware features can also be tested at runtime. - An application always starts in Portrait mode and then transitions to Landscape at a later time. If the device is in Landscape mode at launch time, the transition occurs immediately after launch
- Approximately 5 seconds are available to manage an application state transition; if more time is used, the system may terminate the application for being unresponsive
Classes/objects
- The
UIApplication
class represents the application - The project must provide an application delegate class to customize behaviour. The delegate may also react to transitions from one application state to another (not running, active, inactive, background, suspended)
- An application usually has exactly one
UIWindow
which provides the framework for a hierarchy of views that display the actual screen content - Every project has exactly one main .nib file which is loaded by
UIApplication
; the file name is stored inInfo.plist
- Events are delivered to the responder chain via
UIEvent
which contains one or moreUITouch
objects representing the fingers that touch the screen
Application states and transitions
Notes about the event table:
- The phone call is an example of an interruption event. Other interruption events are handled in exactly the same way, notably the user usually has the choice to ignore the interruption, in which case the application will probably not enter the background state. Another interruption event is calling up the multitasking UI (double-tap Home button) while the application is active.
Event | Notification before entering new state | New state | Notification after entering new state | Remark |
---|---|---|---|---|
- | - | Not running | - | |
Application starts up | - | UIApplicationStateInactive, or UIApplicationStateBackground |
application:didFinishLaunchingWithOptions: | The final state depends on how the application is launched. The next event in this table assumes that the application ended up in UIApplicationStateActive
|
- | UIApplicationStateActive, or UIApplicationStateBackground |
applicationDidBecomeActive:, or applicationDidEnterBackground: | ||
Lock the screen | applicationWillResignActive: | Inactive | - | The "inactive" state has no enumeration value |
Unlock the screen | - | UIApplicationStateActive | applicationDidBecomeActive: | |
Press Home button | applicationWillResignActive: | Inactive | - | |
- | UIApplicationStateBackground | applicationDidEnterBackground: | On devices that do not support multitasking (e.g. systems with iOS earlier than 4.0), applicationWillTerminate: will be invoked instead
| |
- | Suspended | - | The "suspended" state has no enumeration value. Applications may request additional background execution time before they are suspended by the system. Applications may even declare that they support background execution, in which case they are never suspended. | |
Resume application | - | UIApplicationStateBackground | applicationWillEnterForeground: | |
- | UIApplicationStateActive | applicationDidBecomeActive: | ||
Phone call | applicationWillResignActive: | Inactive | - | |
Refuse call | - | UIApplicationStateActive | applicationDidBecomeActive: | |
Phone call | applicationWillResignActive: | Inactive | - | |
Take call | applicationWillResignActive: | Inactive | - | Experiment has confirmed that the application is suspended when the call is taken. |
- | UIApplicationStateBackground | applicationDidEnterBackground: | ||
- | Suspended | - | ||
Hang up | - | UIApplicationStateBackground | applicationWillEnterForeground: | |
- | UIApplicationStateActive | applicationDidBecomeActive: | ||
Press Home button | applicationWillResignActive: | Inactive | - | |
- | UIApplicationStateBackground | applicationDidEnterBackground: | ||
- | Suspended | - | ||
Kill application in the multitasking UI | - | Not running | - | The application receives no notification, the application process is terminated with SIGKILL
|
Summary of recommended steps for each notification:
Notifier | Recommended steps | Remark |
---|---|---|
application:didFinishLaunchingWithOptions: | Restore app to its previous runtime state | Must complete within 5 seconds. Initial UI should be in Portrait orientation, the system will switch to Landscape after this notifier is processed. |
applicationWillResignActive: | Pause operations, put app in "quiescent" state | |
applicationDidBecomeActive: | Do not resume operations automatically if paused, let the user do this in his own time | |
applicationDidEnterBackground: | Prepare app to have its picture taken | Must complete within 5 seconds. Request additional execution time with beginBackgroundTaskWithExpirationHandler: .
|
Save user data and application state information | ||
applicationWillEnterForeground: | ||
applicationWillTerminate: | Save user data and application state information | Must complete within 5 seconds. |
Event handling
Information in this section is taken from the Event Handling Guide for iOS [15].
- 3 event main types
- Touch events
- Shake events
- Remote-control events
- Various event sub types, mostly for remote-control
- Events are delivered via
UIEvent
, which reacts to the messagestype
andsubtype
UIEvent
should not be retained- Event delivery
- Events are generally taken from the event queue by the
UIApplication
, then sent to the application's key window - i.e. theUIWindow
- For touch events, the
UIWindow
finds the view where the touch occurred by hit-testing the views in the view hierarchy, starting from the top-level view. The hit-test view may then respond to the event; if it doesn't, the event goes to the first responder and then travels up the responder chain - Shake and remote-control events immediately go to the first responder because they are not associated with the screen
- A touch object is associated with its hit-test view for its lifetime, even if the touch represented by the object subsequently moves outside the view
- Events are generally taken from the event queue by the
- For a touch event, a single
UIevent
object groups multipleUITouch
objects; thoseUITouch
objects together describe the entire multi-touch sequence - A touch object is persistent for a given finger during a sequence, and UIKit mutates it as it tracks the finger throughout it
- The attributes being mutated are
- Phase of the touch (UITouchPhaseBegan, UITouchPhaseMoved, UITouchPhaseEnded)
- Touch location in a view
- Previous touch location
- Touch timestamp
- The "Event Handling Guide" [15] contains extensive examples how to recognize gestures and handle touch events in general
- However, it is much simpler to use gesture recognizers to detect various established gestures (tap, swipe, pinch, etc.). Basic usage:
- Instantiate the gesture recognizer
- Attach it to the view receiving touches
- Configure it, and assign it an action selector and a target object
- When the gesture recognizer recognizes its gesture, it sends an action message to the target, allowing the target to respond to the gesture
- Sometimes a gesture is of a continuous nature (i.e. pinching); in these cases, the gesture recognizer sends a continuous stream of action messages until the gesture ends
- Multiple gesture recognizers can be attached to a view; if required they can be made to interact in one of the following ways:
- One gesture recognizer must fail for another one to receive any touch events at all; for instance, if both single and double taps should trigger different actions, the double tap recognizer must be made to fail first before the single tap recognizer is allowed to receive and analyze any touch events. The problem here is that there will be a lag between the user's touches and the gesture being recognized, because the second recognizer must wait for the first recognizer to finish its analysis
- Multiple gesture recognizers can be made to attempt to recognize gestures simultaneously
View programming
Views
Information for this section is taken almost entirely from the "View Programming Guide" [13].
- The top-level UI element in an iOS app is its window (an instance of
UIWindow
)- The window is not visible but provides a container for views
- Typically an application has exactly one window; more windows are needed only for special apps, e.g. ones that support external displays for video out
- Views (instances of
UIView
or one of its subclasses) define a rectangular region on the screen and handle the drawing and touch events in that region- With this rationale in mind, we can see that even interactive GUI elements (e.g. buttons) are also views, although we might not think of them as such
- However, the view for these GUI elements is sometimes not accessible directly, instead the programmer must work through a wrapper class that exposes an interface suitable for manipulating the GUI element type represented by the wrapper
- A view can also act as a parent for other views and coordinate the placement and sizing of those views.
- Views are organized in a hierarchic structure
- The parent view is called the "superview"
- The child view is called the "subview"
- A superview stores its subviews in an ordered array, the order in which subviews appear in that array affects their visibility should they overlap: Views that are added later (or are moved to the end of the subview array) appear on top of their preceding siblings
UIView
uses an on-demand drawing model for presenting content- When a view first appears on the screen, the system asks it to draw its content
- The system captures a snapshot of this content and re-uses that snapshot as long as the view's content never changes
- If the content changes, the system must be notified by invalidating the view (using either the
setNeedsDisplay
orsetNeedsDisplayInRect:
method) - The redraw operation is not performed immediately, instead the system waits until the end of the current run loop before initiating the next draw operation
- This provides the opportunity to invalidate multiple views or rectangles, make changes to the view hierarchy, or show/hide/resize/reposition any views that require it. All of these changes are then reflected at the same time when the next draw cycle occurs.
- Coordinates
- The coordinate system in the UIKit, and therefore when interacting with
UIView
, has its origin in the top-left corner. This is different in other technologies such as Core Graphics - A view's
frame
property specifies the view's frame rectangle in its superview's coordinate system - A view's
bounds
property specifies the view's bounds rectangle (i.e. its size and origin) in its own coordinate system - A view's
center
property specifies the center point of the view in the superview’s coordinate system - Clipping to a view's superview frame must be specifically enabled by setting the
clipsToBounds
property - The
frame
andcenter
properties are intended to be used to change the view's geometry - The
bounds
property is intended to be used during drawing
- The coordinate system in the UIKit, and therefore when interacting with
- Points and pixels
- Coordinates, distances, etc. are usually measured in points, not pixels
- Exceptions are pixel-based technologies such as OpenGL, or when a program needs to work with images
- One point does not necessarily correspond to one pixel on the screen
- iPhone screen dimensions in points: 320x480
- iPad screen dimensions in points: 768x1024
- A very important and illuminating section in the "View Programming Guide" [13] is "The Runtime Interaction Model for Views" (under "View and Window Architecture"): It provides an overview of the chain of events when the user interacts with a view, or when a programmatic change is triggered, and which are the points of extension where an application is allowed by iOS/UIKit to react to these events.
- Another interesting section in the same guide is "Creating and Configuring View Objects" (under "Views"): It explains how views can be created programmatically instead of through InterfaceBuilder
- Last but not least, the section "Defining a Custom View" (under "Views"), which includes a useful checklist for implementing custom views, i.e. your own subclass of
UIView
Controllers
Information for this section is taken almost entirely from the "View Controller Programming Guide" [12]. All types of view controllers have a dedicated section in this guide that explains their use in depth.
- Custom view controllers are subclasses of either
UIViewController
orUITableViewController
- An interesting section in the "View Controller Programming Guide" [12] is "Custom View Controllers": It explains many details about how custom view controllers should be implemented, including how to create controllers and their views programmatically instead of through InterfaceBuilder.
- A very detailed sub-section also explains how to handle interface orientation changes
- Table view controllers (
UITableViewController
) manage table views. There is a special guide "Table View Programming Guide" [14] that deals with this type of controller and view. - There are several types of so-called "container" view controllers. These are controllers built-in to iOS which manage other view controllers and define the navigational relationships among them
- Navigation controllers (
UINavigationController
instances) manage stacks of other view controllers. In addition, it can be very effective in simple scenarios to use a navigation controller because the navigation bar it displays can be easily customized with a few GUI controls (e.g. "Cancel" and "Done" buttons) - Tab Bar controllers (
UITabBarController
instances) manage stacks of other view controllers - On iPad,
UISplitViewController
manages the implementation of a master-detail interface, where both the master and detail portions of the interface are themselves managed by view controllers
- Navigation controllers (
- Modal view controllers
- Any view controller can be presented modally
- The purpose of modal view controllers is to interrupt the current workflow temporarily to gather or present information
- The way how the modal view controller is presented can make it more or less obvious to the user that "something modal" is going on. For instance, if the view presented by the modal view controller scrolls up from the bottom and covers only half of the screen, the "interrupt" nature of the modal view controller is very obvious (an example is when a message in the Mail app is replied to/forwarded). In contrast, if the new view fully obscures the entire screen, there is more of a "workflow" impression (an example is when a new event is created in the Calendear app).
- Recipe to implement modal view controllers
- The modal view controller defines a "delegate" property
- It also defines a protocol for the delegate to implement
- The parent controller sets the "delegate" property of the modal view controller to
self
- The parent controller implements the delegate protocol
- The parent controller displays the modal view controller
[self presentModalViewController:newGameController animated:YES];
- The modal view controller invokes the delegate method on its delegate when it has finished interacting with the user
- The delegate method queries the modal view controller for the information that was gathered, then dismisses the modal view controller
[self dismissModalViewControllerAnimated:YES];
- Popover controllers
- Popovers are available in iPad applications only
- TODO
View management cycle
- A view controller manages its view in a load, and in an unload cycle
- When the view is first requested, it is loaded into memory
- When a low-memory warning is received, a view controller may try to unload the view; this includes releasing the view object
- The cycle begins again when the view is requested the next time
- The load cycle
- The load cycle is triggered when the view controller's
view
property is accessed and the view is not in memory - First the
loadView
method is invoked. The default implementation tries to load the view from an appropriate .nib file. The method may be overridden to provide code that creates a view programmatically. - Second the
viewDidLoad
is invoked to perform any additional load-time tasks. This method is intended to be overridden.
- The load cycle is triggered when the view controller's
- The unload cycle
- The unload cycle is triggered when the application receives a low-memory warning from the system
- First, each view controller's
didReceiveMemoryWarning
method is invoked. The default implementation unloads the view if it determines that "it is safe to do so" (whatever that means). The method may be overridden to provide code that releases custom data, but the overriding implementation must not release the view on its own, instead it must invoke the default implementation at some point to do so - Second, the
viewDidUnload
method is invoked, but only if the view is actually released by the default implementation ofdidReceiveMemoryWarning
Animations
For programming details and examples on animation, see the section "Animations" in the "View Programming Guide" [13]. This section also contains links to further animation-related documentation ("Core Animation Programming Guide", "Core Animation Cookbook").
Overview of what can be animated:
- View properties that can be animated
- Position and size changes
- Rotation, scaling and stretching changes
- Transparency changes
- Background color changes
- Animation is also possible when transitioning from one view to another. In this case, the active view controller remains the same
Interface Orientation
The major documentation blocks are
- View Controller Programming Guide for iOS [12], Section "Supporting Multiple Interface Orientations"
- App Programming Guide [7], Section "Advanced App Tricks > Launching in Landscape Mode"
A few basics:
- There is a difference between the device orientation, and the interface orientation
- UIDevice can be queried for the device orientation, but only after the accelerometer has been enabled via
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]
- The interface orientation only knows 4 orientations, whereas the device orientation can also be "face up" or "face down"
- Interface orientation is usually obtained from a view controller's
interfaceOrientation
property - A global source of the current interface orientation is this property:
[UIApplication sharedApplication].statusBarOrientation
The major points for adding support for orientation changes are these
- In the app's
Info.plist
add an array key namedUISupportedInterfaceOrientations
. The array values define which interface orientations the app wants to support. It is possible to specify different sets of interface orientations for each device type by adding the suffix~iphone
and~ipad
to the array key's name. - Add an override of
supportedInterfaceOrientations
to the application window's root view controller which returns the same interface orientations that are also defined inInfo.plist
. During runtime it is possible to let the override return varying values - iOS only allows those interface orientations that are an intersection between the values returned by the override and the values defined inInfo.plist
. - Also add an override of
supportedInterfaceOrientations
to all view controllers that you are presenting over the root view controller, because if a view controller is presented iOS will query the presented view controller instead of the root view controller. - An override of
shouldAutorotate
in the application window's root view controller may also be useful if the app should be able to temporarily disable auto-rotation. The default implementation of that method always returnsYES
, but an override may temporarily returnNO
.
Orientation on app startup
- Really, really, really read the App Programming Guide section mentioned above; it contains all the details, and they are all true. In a nutshell:
- You can only set the initial orientation to be landscape in
Info.plist
if the app does not support portrait at all! - If the app supports portrait and landscape, the app must start in portrait mode and then support rotation to landscape
- Don't be alarmed: The initial rotation to landscape occurs while the launch image is still visible, so the user will not notice the rotation taking place
- Even better: If you supply a landscape launch image, the system will correctly display that launch image if the user holds the device in landscape position
Reacting to interface orientation changes
- Every other version of iOS changes how interface orientation changes are handled in view controllers. At the time of writing, iOS 8 is current and if the changes Apple made in that version appear to be stable I may write more about this topic.
Debugging tips
- Colorize your views' background. This is especially important for those intermediate views that are not visible at all. By giving each view a specific background color you can sometimes observe whether or not a view is changing it's bounds
- Reproduce the problem in a small test project that you create from scratch. When you run into trouble adding orientation support to an existing application, you may sometimes become confused and start looking for the problem in area X, while the problem actually is buried in area Y. Starting a new project from scratch usually helps to focus and clear the mind of any doubts that something is "inexplicably not working"
Interface Builder
Interface Builder notes
- Adding a navigation or table view controller to a tab bar controller in IB: Always drag the navigation or table view controller from the library - do not just change the class name of a generic view controller to
UINavigationController
orUITableViewController
. Note that changing the class name is OK if the controller object is of a custom class. - Combining navigation with tab bar controller
- Add the navigation controller to the tab bar controller as described above
- Configure the navigation controller's root view controller (!), not the navigation controller itself: Set the nib file name, and possibly the class name
- In the secondary nib file (the one that is loaded by the root view controller): Set the root view controller as the File's Owner
Questions
React to being loaded from .nib
Implement the following method:
/// @note This is a method from the UINibLoadingAdditions category (an addition /// to NSObject, defined in UINibLoading.h). Although it has the same purpose, /// the implementation via category is different from the NSNibAwaking informal /// protocol on the Mac OS X platform. - (void) awakeFromNib { [...] }
In the case of UIView
subclasses, the following method can also be used:
- (id)initWithCoder:(NSCoder *)decoder { [...] }
Implement a splash screen
A Launch Image is a static image that iOS displays for a couple of seconds while the application starts up. The iOS Human Interface Guidelines [8] explicitly say to avoid mis-using the Launch Image as a splash screen.
If an application wants to have a dynamically changing startup screen (e.g. a screen with some sort of progress indicator), it needs to create a separate view and view controller for this. Unfortunately, the Launch Image cannot be avoided and replaced by the custom splash screen, because presence of the Launch Image is mandatory for apps being distributed over the App Store.
References
- ↑ App Development Overview (especially section "Preparing the Development Team")
- ↑ iOS Team Administration Guide
- ↑ Tools Workflow Guide for iOS
- ↑ 4.0 4.1 Technical Note TN2250
- ↑ iOS Reference Library
- ↑ iOS Development Guide
- ↑ 7.0 7.1 7.2 iOS Application Programming Guide
- ↑ 8.0 8.1 iOS Human Interface Guidelines
- ↑ Foundation Framework Reference
- ↑ UIKit Framework Reference
- ↑ UIKit Function Reference
- ↑ 12.0 12.1 12.2 12.3 View Controller Programming Guide for iOS
- ↑ 13.0 13.1 13.2 13.3 View Programming Guide iOS
- ↑ 14.0 14.1 Table View Programming Guide iOS
- ↑ 15.0 15.1 Event Handling Guide for iOS