Monday, March 23, 2009

Apple Push Notification Service (APNS)

The Apple Push Notification Service will be launched in this summer and this is one of interesting features of iPhone OS 3.0.

Since the SSL certificate for the APNS for the developer's app is not yet available (update: available now on April 9) in the developer program portal, we need to simulate and test it in our environment at this moment. To prepare for this, we need a client program and a server program (for testing with the client) implementing the TLS communication protocol.

(1) Requirements
The requirement of communication with Apple Push Notification Service (APNS) is described in the "Apple Push Notification Service Programming Guide" and for the developer's view, we need to have a client program to communicate with and send the payload to the APNS

- a "raw" (binary) socket interface which is asynchronous and one-way from developer to APNS
- The binary interface is available through gateway.push.apple.com, port 2195
- use TLS (or SSL) to establish a secured communications channel
- The SSL certificate (will be provided from Apple per Application ID from developer portal) is required for these connections
- should present this certificate to APNS at connection time using peer-to-peer authentication.
- should also retain connections with APNS across multiple notifications.

(2) Payload
The maximum size allowed for a notification payload is 256 bytes;
Example of the notification payload

Command : 1 byte (0x00)
Device Token length : 2 bytes (0x00 0x20)
Device Token(binary) : 32 bytes
Payload length : 2 bytes
Payload Content (max 256 bytes): e.g.

{
"aps" : {
"alert" : {"loc-key":"%@ and %@ have invited you to Dinner","loc-args":["Jenna","Frank"]},
"badge" : 9
"sound" : "happysound.aiff"
},
"acme1" : "custom property",
"acme2" : 42,
"acme3" : [5,8]
}


The following example shows the payload message of
{"aps":{"alert":"Message from javacom","badge":9}}
in HexEdit Screen




#define DEVICE_BINARY_SIZE 32
#define MAXPAYLOAD_SIZE 256


(3) Pseudocode for this client side program (My iniitial draft for C Code)


Client code for TLS v1 protocol
Needs openssl crypto lib

At first
Initialisation of TLS Context and return SSL Context
SSL_CTX *ctx;
SSL *ssl;

SSL_CTX object is created as a framework to establish TLS/SSL enabled connections
use SSL_CTX_new to create a new context
SSL_CTX should include the tls stuff for SSL certificate handling
use SSL_CTX_set_client_cert_cb(ctx, client_cert_cb) to provide client SSL cert.

socket is created for the APNS
int sock;
struct sockaddr_in server;

connect socket
connect(sock, (struct sockaddr *)&server, sizeof(server))

Then associate the network connection with the object

create a new SSL structure for a connection
SSL_new(ctx)))

connect the SSL object with a socket file descriptor
SSL_set_app_data(ssl, conn);
SSL_set_fd(ssl, sock)

Set ssl to work in client mode (that is to connect)
SSL_set_connect_state(ssl);

Then the TLS/SSL handshake is performed
Connect SSL
SSL_connect
If connect successful
Compose Payload
sendPayload using SSL_write (this part was given by Apple)

If connect unsuccessful, handle error

If Payload sent or reach maximum retries
Then Shut down the TLS/SSL connection.
SSL_shutdown(ssl);
SSL_free(ssl);
Destroy SSL Context
SSL_CTX_free(ctx); ctx = NULL
close(sock);




(4) Other aspects (TO-DOs)
- Keep the definitive count of data items remaining to be downloaded.
- Regularly connect with the feedback web server and fetch the current list of those devices that have repeatedly reported failed-delivery attempts.
- iPhone client program

see update here
http://iphonesdkdev.blogspot.com/2009/04/apns-client-development-certificate.html
.
.
.

Friday, March 20, 2009

3G Tethering & MMS for iPhone OS 3.0 beta




Use this shell command to find out the ipcc file for your country
curl -s -L http://phobos.apple.com/version | grep -i carrier

Then follow these instructions below to amend the bundle contents

Instruction for 3G Tethering is here
http://www.iphonealley.com/news/hacker-enables-usb-tethering-in-30-beta

Instruction for MMS is here
http://forums.macrumors.com/showthread.php?t=671426


You can also change the carrier logo, if you modified the png files in the bundle

.
.
.

Saturday, February 21, 2009

Tuesday, February 3, 2009

How to re-codesign iPhone binary ?

The codesign certificate from Apple is used by developers to compile the source code and deploy their iPhone Apps to device.

Have you ever think of how to re-codesign an already compiled iPhone binary and deploy that app to non-jailbroken iPhone without the source code and without re-compiling in Xcode ? That means only re-codesign the binary with the developer certificate again so that XCode can deploy it to development devices such as iPhone / iPod Touch. By using this method, you can patch the existing binary / add localization bundles or change the graphic files before re-codesign and deployment to device.

For example, there was a very nice app called NetShare which was pulled from the App Store, sometimes ago.

Would it be nice, if I can re-codesign (using the developer certificate) the NetShare binary and deploy it to my iPhone 3G, no jailbreak required. I can use it for tethering in cellular wireless.

I have done it, and the developer certificate is used to change the codesign signature and the app can be installed to non-jailbroken iPhone / iPod Touch successfully. This requires a hack on the original ipa file downloaded from App Store.

The following screen dump is captured from my iPod Touch second generation, no jailbreak. (I did not use redsn0w)

In my testing in iPhone 3G, Netshare can tether the 3G cellular networking using Mac OS X using the SOCKS Proxy. Safari Web Browing, iChat and iTunes work. But Microsoft Messenger and Mail do not work.




To implement the re-codesign, you first need a decrypted ipa, there are lots of them out there in the net. Don't ask me to give you.

Part I Decrypted IPA
Please take note that you don't need this method to decrypt the IPA file, if you already have the decrypted one downloaded from the net (those ipa files floating in the net are already decrypted).

If you have that particular app installed in iPhone from AppStore directly, it needs to be decrypted in order to be useful. One of the decrypt methods is to use a jailbreak iPhone and run the script (source from pr0x.org Forum) below in iPhone to create the decrypted ipa.
To use this method you must have installed the app from App Store in jailbreak iPhone plus the following packages from Cydia
apt-get install com.ericasadun.utilities gdb gawk zip ldid odcctools

To find out the app names with descending date order that your iPhone have installed, run this command in iPhone
find /var/mobile/Applications/ -iname *.app | xargs -0 ls -ldt

and use this command to generated the decrypted ipa e.g.
./DCrypt.sh "Monkey Ball"

DCrypt.sh Select all

#!/bin/sh
#
# DeCrypt - v1.1 (2008-10-21)
# - v1.1 (2008-10-21)
# FloydianSlip
#
# Heavily based on xcrack
#
# Many thanks to:
# puy0, SaladFork, Flox, Flawless
#

echo "DeCrypt 1.1 (2008-10-21)"
echo "FloydianSlip"
echo

if [ ! -e /usr/bin/plutil ]; then
echo "Cannot find plutil (apt-get install com.ericasadun.utilities)"
exit 1
fi

if [ ! -e /usr/bin/gdb ]; then
echo "Cannot find gdb (apt-get install gdb)"
exit 1
fi

if [ ! -e /usr/bin/otool ]; then
echo "Cannot find otool (apt-get install odcctools)"
exit 1
fi

if [ ! -e /usr/bin/ldid ]; then
echo "Cannot find otool (apt-get install ldid)"
exit 1
fi


if [ ! -e /usr/bin/awk ]; then
echo "Cannot find awk (apt-get install gawk)"
exit 1
fi

if [ ! -e /usr/bin/zip ]; then
echo "Cannot find zip (apt-get install zip)"
exit 1
fi

if [ $# -ne 1 ]; then
echo "Usage: $(basename $0) <ApplicationName>"
echo
exit 1
fi

AppInput=$1

if [ -d "$AppInput" ]; then
tempLoc=$AppInput
else
echo "Locating $AppInput"
tempLoc=$(find /var/mobile/Applications -iname "$AppInput.app")
if [ -z "$tempLoc" ]; then
echo "Unable to locate $AppInput"
exit 1
fi
AppCount=$(find /var/mobile/Applications -iname "$AppInput.app" | wc -l)
if [ $AppCount -gt 1 ]; then
echo "Found two installation directories:"
find /var/mobile/Applications -iname "$AppInput.app"
exit 1
fi
fi

AppPath=$(dirname "$tempLoc")
AppName=$(basename "$tempLoc")
AppExec=$(plutil -v CFBundleExecutable "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')
AppVer=$(plutil -v CFBundleVersion "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')
AppDisplayName=$(plutil -v CFBundleDisplayName "$tempLoc/Info.plist" 2>&1 | awk -F "] " '{ print $2 }')

if [ ! -d "$AppPath" ]; then
echo "Unable to locate original installation directory"
exit 1
fi

if [ ! -d "$AppPath/$AppName" ]; then
echo "Unable to locate .app directory"
exit 1
fi

if [ ! -e "$AppPath/$AppName/$AppExec" ]; then
echo "Unable to locate executable"
exit 1
fi

echo "Found $AppName"

echo "Creating directories"
WorkDir="/tmp/DecryptApp-$(date +%Y%m%d-%H%M%S)"
NewAppDir="$HOME/Documents/Decrypted"

if [ -e "$WorkDir" ]; then
rm -rf "$WorkDir"
fi

mkdir -p "$WorkDir"

if [ ! -e "$NewAppDir" ]; then
mkdir -p "$NewAppDir"
fi

if [ ! -d "$WorkDir" -o ! -d "$NewAppDir" ]; then
echo "Unable to create Directories"
exit 1
fi

echo "Copying application files"

cp -a "$AppPath/$AppName/" "$WorkDir/"

if [ ! -e "$WorkDir/$AppName/$AppExec" ]; then
echo "Unable to copy application files"
rm -fr "$WorkDir"
exit 1
fi

echo "Analyzing application"

CryptID=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptid | awk '{print $2}')
if [ $CryptID -ne "1" ]; then
echo "Application is not encrypted"
rm -fr "$WorkDir"
exit 1
fi

CryptSize=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptsize | awk '{print $2}')
if [ ! $CryptSize ]; then
echo "Unable to find CryptSize"
rm -fr "$WorkDir"
exit 1
fi

CryptOff=$(otool -l "$WorkDir/$AppName/$AppExec" | grep cryptoff | awk '{print $2}')
if [ ! $CryptOff ]; then
echo "Unable to find CryptOff"
rm -fr "$WorkDir"
exit 1
fi

echo "Locating and patching CryptID"

# "/System/Library/Frameworks" in hex
PathAsHex="2f53797374656d2f4c6962726172792f4672616d65776f726b73"

# - Convert to hex on 1 long line, only take stuff before the path string,
# - Convert to 1 byte set per line, find 0x01 (line number is offset in the real file),
# - Strip newlines, reverse the order
oneLocations=($(od -A n -t x1 -v "$WorkDir/$AppName/$AppExec" | \
tr -d ' ','\n' | \
sed "s/$PathAsHex.*\$//" | \
sed "s/../&\n/g" | \
grep -n -s 01 | \
cut -d : -f 1 | \
sort -nr | \
tr "\n" " "))

for TryOffset in "${oneLocations[@]}"; do
cp -a "$WorkDir/$AppName/$AppExec" "$WorkDir/$AppName/$AppExec.trying"
foo=$(echo -ne "\x00" | dd bs=1 seek=$((TryOffset - 1)) conv=notrunc status=noxfer of="$WorkDir/$AppName/$AppExec.trying" 2>&1> /dev/null)
cid=$(otool -l "$WorkDir/$AppName/$AppExec.trying" | grep cryptid | awk '{print $2}')
if [ $cid -eq 0 ]; then
break
fi
rm "$WorkDir/$AppName/$AppExec.trying"
done

if [ ! -e "$WorkDir/$AppName/$AppExec.trying" ]; then
echo "Unable to find CryptID"
rm -fr "$WorkDir"
exit 1
fi

mv "$WorkDir/$AppName/$AppExec.trying" "$WorkDir/$AppName/$AppExec"

echo "Dumping unencrypted data from application"

echo -e "set sharedlibrary load-rules \".*\" \".*\" none\r\n\
set inferior-auto-start-dyld off\r\n\
set sharedlibrary preload-libraries off\r\n\
set sharedlibrary load-dyld-symbols off\r\n\
handle all nostop\r\n\
break *0x2000\r\n
commands 1\r\n\
dump memory $WorkDir/dump.bin 0x2000 $(($CryptSize + 0x2000))\r\n\
kill\r\n\
quit\r\n\
end\r\n\
start" > $WorkDir/batch.gdb

foo=$(gdb -q -e "$AppPath/$AppName/$AppExec" -x $WorkDir/batch.gdb -batch 2>&1> /dev/null)

rm $WorkDir/batch.gdb

echo "Verifiying data dump"

DumpSize=$(stat -c%s "$WorkDir/dump.bin")
if [ "$DumpSize" != "$CryptSize" ]; then
echo "Memory dump is not the right size or does not exist"
rm -fr "$WorkDir"
exit 1
fi

echo "Replacing encrypted data with data dump"
foo=$(dd seek=4096 bs=1 conv=notrunc if="$WorkDir/dump.bin" of="$WorkDir/$AppName/$AppExec" 2>&1> /dev/null)
rm "$WorkDir/dump.bin"

echo "Signing the application"
foo=$(ldid -s "$WorkDir/$AppName/$AppExec" 2>&1> /dev/null)
plutil -s 'SignerIdentity' -v 'Apple iPhone OS Application Signing' "$WorkDir/$AppName/Info.plist" 2>&1> /dev/null

if [ -e "$WorkDir/$AppName/SC_Info" ]; then
echo "Removing SC_Info"
rm -fr "$WorkDir/$AppName/SC_Info"
fi

if [ -e "$WorkDir/$AppName/_CodeSignature" ]; then
echo "Removing _CodeSignature"
rm -fr "$WorkDir/$AppName/_CodeSignature"
fi

if [ -h "$WorkDir/$AppName/CodeResources" ]; then
echo "Removing CodeResources"
rm -fr "$WorkDir/$AppName/CodeResources"
fi

if [ -e "$WorkDir/$AppName/ResourceRules.plist" ]; then
echo "Removing ResourceRules.plist"
rm -fr "$WorkDir/$AppName/ResourceRules.plist"
fi

echo "Building .ipa"

mkdir -p "$WorkDir/Payload"
if [ ! -e "$WorkDir/Payload" ]; then
echo "Failed to create Payload directory"
rm -fr "$WorkDir"
exit 1
fi
mv "$WorkDir/$AppName" "$WorkDir/Payload/"

echo "Copying iTunesArtwork"

if [ -e "$AppPath/iTunesArtwork" ]; then
cp -a "$AppPath/iTunesArtwork" "$WorkDir/"
else
echo "Unable to find iTunesArtwork"
fi

echo "Compressing the .ipa"
IPAName=$NewAppDir/$(echo $AppDisplayName | sed -e "s: :_:g")-v$AppVer.ipa
cd "$WorkDir"
zip -m -r "$IPAName" * 2>&1> /dev/null
cd - 2>&1> /dev/null
if [ ! -e "$IPAName" ]; then
echo "Failed to compress the .ipa"
rm -fr "$WorkDir"
exit 1
fi

echo "Removing temporary files"
rm -rf "$WorkDir"

echo "Done"
echo "Created decrypted .ipa at $IPAName"


Part II Installation of XCode Template

curl -O http://apiexplorer.googlecode.com/files/CrappStore.zip
unzip -o CrappStore.zip -d "/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Project Templates/Application/"



Part III XCode Build & Go

To install the decrypted ipa to non-jailbreak iPhone via XCode, you need the followings and a fully functional build & go iPhone device with iPhone SDK development environment with all Official certificates and Provisioning Profiles from Apple installed in Mac and iPhone /iPod Touch device
1) The XCode Template called CrappStore (see installation instruction in Part II above)
2) Official Developer Certificate from Apple installed in Mac
3) Official Development Provisioning Profile from Apple installed in Mac and iPhone / iPod Touch for development
4) XCode and iPhone SDK (I have tested it on iPhone SDK 2.2.1, but should work on earlier versions) installed in Mac (Intel)

Steps to Build & Go in Mac Xcode
1) Get the project name from the ipa file unzip -l Monkey_Ball-v1.02.ipa
2) Create a new project from the CrappStore XCode Template with Project Name same as the decrypted ipa e.g. "Monkey Ball"
3) Copy the decrypted ipa file (with extension .ipa) to the newly created Project folder (only copy one .ipa file to that project folder)
e.g. ~/Projects/Monkey\ Ball/Monkey_Ball-v1.02.ipa
4) Make sure iPhone / iPod Touch is connected to USB and recognized by XCode
5) Select Device - iPhone OS 2.0 (Project Settings)
6) Click Build & Go to Device Release. Or alternatively, you can simply build and then drag the product to the device's app list.
Done

It is possible to have other methods, but using the Xcode is the easiest one. Moreover, you can patch / mod it before deployment to device. If you have modified the app, remember to delete the ipa file in the project folder, so that it will not be unzipped again and overwrite your modding.






Thursday, January 29, 2009

How to skip provisioning profile for iPhone SDK 2.2.1 (build 9M2621a)

The trick to skip provisioning profile for iPhone SDK 2.1.1 (build 9M2621a) still works

Just backup and edit the file and add the magic words as shown below highlighted in red color

/Developer/Platforms/iPhoneOS.platform/Info.plist

Info.plist:Select all

<key>OverrideProperties</key>
<dict>
<key>CODE_SIGN_CONTEXT_CLASS</key>
<string>XCiPhoneOSCodeSignContext</string>
<key>DEBUG_INFORMATION_FORMAT</key>
<string>dwarf-with-dsym</string>
<key>EMBEDDED_PROFILE_NAME</key>
<string>embedded.mobileprovision</string>
<key>SDKROOT</key>
<string>iphoneos2.2.1</string>
<key>PROVISIONING_PROFILE_ALLOWED</key>
<string>NO</string>
<key>PROVISIONING_PROFILE_REQUIRED</key>
<string>NO</string>

</dict>


Please remember to restart your Xcode after the amendment above.

For MobileInstallation patch, please use my package (updated to support firmware 2.2.1) as posted here
http://hackint0sh.org/forum/showpost.php?p=340693&postcount=14

Related articles from this blog
http://iphonesdkdev.blogspot.com/2008/11/how-to-skip-provisioning-profile-for.html
http://iphonesdkdev.blogspot.com/2008/09/xcode-template-for-pwned-iphone-device.html




Sunday, January 25, 2009

Objective C 2.0, Foundation Framework Quick Reference






Data Type Conversion Rules
The Objective-C compiler adheres to very strict rules when it comes to evaluating expressions that consist of different data types.

The following summarizes the order in which conversions take place in the evaluation of two operands in an expression:

1. If either operand is of type long double, the other is converted to long double, and that is the type of the result.

2. If either operand is of type double, the other is converted to double, and that is the type of the result.

3. If either operand is of type float, the other is converted to float, and that is the type of the result.

4. If either operand is of type _Bool, char, short int, or bit field,[1] or of an enumerated data type, it is converted to int.

5. If either operand is of type long long int, the other is converted to long long int, and that is the type of the result.

6. If either operand is of type long int, the other is converted to long int, and that is the type of the result.

7. If this step is reached, both operands are of type int, and that is the type of the result.
































Common NSString Methods
MethodDescription
+(id) stringWithContentsOfFile: path encoding: enc error: err Creates a new string and sets it to the path contents of a file specified by path using character encoding enc, returning error in err if non-nil
+(id) stringWithContentsOfURL: url encoding: enc error: err Creates a new string and sets it to the contents of url using character encoding enc, returning error in err if non-nil
+(id) string Creates a new empty string
+(id) stringWithString: nsstring Creates a new string, setting it to nsstring
-(id) initWithString: nsstring Sets a newly allocated string to nsstring
-(id) initWithContentsOfFile: path encoding: enc error: err Sets a string to the contents of a file specified by path
-(id) initWithContentsOfURL: url encoding enc error: err Sets a string to the contents of url (NSURL *) url using character encoding enc, returning error in err if non-nil
-(NSUInteger) length Returns the number of characters in the string
-(unichar) characterAtIndex: i Returns the Unicode character at index i
-(NSString *) substringFromIndex: i Returns a substring from the character at i to the end
-(NSString *) substringWithRange: range Returns a substring based on a specified range
-(NSString *) substringToIndex: i Returns a substring from the start of the string up to the character at index i
-(NSComparator *) caseInsensitiveCompare: nsstring Compares two strings, ignoring case
-(NSComparator *) compare: nsstring Compares two strings
-(BOOL) hasPrefix: nsstring Tests whether a string begins with nsstring
-(BOOL) hasSuffix: nsstring Tests whether a string ends with nsstring
-(BOOL) isEqualToString: nsstring Tests whether two strings are equal
-(NSString *) capitalizedString Returns a string with the first letter of every word capitalized (and the remaining letters in each word converted to lower case)
-(NSString *) lowercaseString Returns a string converted to lower case
-(NSString *) uppercaseString Returns a string converted to upper case
-(const char *) UTF8String Returns a string converted to a UTF-8 C-style character string
-(double) doubleValue Returns a string converted to a double
-(float) floatValue Returns a string converted to a floating value
-(NSInteger) integerValue Returns a string converted to an NSInteger integer
-(int) intValue Returns a string converted to an integer












Common NSMutableString Methods
MethodDescription
+(id) stringWithCapacity: size Creates a string initially containing size characters.
-(id) initWithCapacity: size Initializes a string with an initial capacity of size characters.
-(void) setString: nsstring Sets a string to nsstring.
-(void) appendString: nsstring Appends nsstring to the end of the receiver.
-(void) deleteCharactersInRange: range Deletes characters in a specified range.
-(void) insertString: nstring atIndex: i Inserts nsstring into the receiver starting at index i.
-(void) replaceCharactersInRange: range withString: nsstring Replaces characters in a specified range with nsstring.
-(void) replaceOccurrencesOf String: nsstring withString: nsstring2 options: opts range: range Replaces all occurrences of nsstring with nsstring2 within a specified range and according to options opts. Options can include a bitwise-ORed combination of NSBackwardsSearch (the search starts from the end of range), NSAnchoredSearch (nsstring must match from the beginning of the range only), NSLiteralSearch (performs a byte-by-byte comparison), and NSCaseInsensitiveSearch.













Common NSArray Methods
MethodDescription
+(id) arrayWithObjects: obj1, obj2, ... nil Creates a new array with obj1, obj2, ... as its elements
-(BOOL) containsObject: obj Determines whether the array contains obj (uses the isEqual: method)
-(NSUInteger) count Indicates the number of elements in the array
-(NSUInteger) indexOfObject: obj Specifies the index number of the first element that contains obj (uses the isEqual: method)
-(id) objectAtIndex: i Indicates the object stored in element i
-(void) makeObjectsPerform Selector: (SEL) selector Sends the message indicated by selector to every element of the array
-(NSArray *) sortedArrayUsing Selector: (SEL) selector Sorts the array according to the comparison method specified by selector
-(BOOL) writeToFile: path automically: (BOOL) flag Writes the array to the specified file, creating a temporary file first if flag is YES













Common NSMutableArray Methods
MethodDescription
+(id) array Creates an empty array
+(id) arrayWithCapacity: size Creates an array with a specified initial size
-(id) initWithCapacity: size Initializes a newly allocated array with a specified initial size
-(void) addObject: obj Adds obj to the end of the array
-(void) insertObject: obj atIndex: i Inserts obj into element i of the array
-(void) replaceObjectAtIndex: i withObject: obj Replaces element i of the array with obj
-(void) removeObject: obj Removes all occurrences of obj from the array
-(void) removeObjectAtIndex: i Removes element i from the array, moving down elements i+1 through the end of the array
-(void) sortUsingSelector: (SEL) selector Sorts the array based on the comparison method indicated by selector











Common NSDictionary Methods
MethodDescription
+(id) dictionaryWithObjectsAndKeys: obj1, key1, obj2, key2, ..., nil Creates a dictionary with key-object pairs {key1, obj1}, {key2, obj2}, ...
-(id) initWithObjectsAndKeys: obj1, key1, obj2, key2,..., nil Initializes a newly allocated dictionary with key-object pairs {key1, obj1}, {key2, obj2}, ...
-(unsigned int) count Returns the number of entries in the dictionary
-(NSEnumerator *) keyEnumerator Returns an NSEnumerator object for all the keys in the dictionary
-(NSArray *) keysSortedByValueUsingSelector: (SEL) selector Returns an array of keys in the dictionary sorted according to the comparison method selector specifies
-(NSEnumerator *) objectEnumerator Returns an NSEnumerator object for all the values in the dictionary
-(id) objectForKey: key Returns the object for the specified key









Common NSMutableDictionary Methods
MethodDescription
+(id) dictionaryWithCapacity: size Creates a mutable dictionary with an initial specified size
-(id) initWithCapacity: size Initializes a newly allocated dictionary to be of an initial specified size
-(void) removeAllObjects Removes all entries from the dictionary
-(void) removeObjectForKey: key Removes the entry for the specified key from the dictionary
-(void) setObject: obj forKey: key Adds obj to the dictionary for the key key and replaces the value if key already exists













Common NSSet Methods
MethodDescription
+(id) setWithObjects: obj1, obj2, ..., nil Creates a new set from the list of objects
-(id) initWithObjects: obj1, obj2, ..., nil Initializes a newly allocated set with a list of objects
-(NSUInteger) count Returns the number of members in the set
-(BOOL) containsObject: obj Determines whether the set contains obj
-(BOOL) member: obj Determines whether the set contains obj (using the isEqual: method)
-(NSEnumerator *) objectEnumerator Returns an NSEnumerator object for all the objects in the set
-(BOOL) isSubsetOfSet: nsset Determines whether every member of the receiver is present in nsset
-(BOOL) intersectsSet: nsset Determines whether at least one member of the receiver appears in nsset
-(BOOL) isEqualToSet: nsset Determines whether the two sets are equal












Common NSMutableSet Methods
MethodDescription
-(id) setWithCapacity: size Creates a new set with an initial capacity to store size members
-(id) initWithCapacity: size Sets the initial capacity of a newly allocated set to size members
-(void) addObject: obj Adds obj to the set
-(void) removeObject: obj Removes obj from the set
-(void) removeAllObjects Removes all members of the receiver
-(void) unionSet: nsset Adds each member of nsset to the receiver
-(void) minusSet: nsset Removes all members of nsset from the receiver
-(void) intersectSet: nsset Removes all members from the receiver that are not also in nsset















Common NSFileManager Methods
MethodDescription
-(NSData *) contentsAtPath: path Reads data from a file
-(NSData *) createFileAtPath: path contents: (NSData *) data attributes: attr Writes data to a file
-(BOOL) removeFileAtPath: path handler: handler Removes a file
-(BOOL) movePath: from toPath: to handler: handler Renames or moves a file (to cannot already exist)
-(BOOL) copyPath: from toPath: to handler: handler Copies a file (to cannot already exist)
-(BOOL) contentsEqualAtPath: path1 andPath: path2 Compares contents of two files
-(BOOL) fileExistsAtPath: path Tests for file existence
-(BOOL) isReadableFileAtPath: path Tests whether file exists and can be read
-(BOOL) isWritableFileAtPath: path Tests whether file exists and can be written
-(NSDictionary *) fileAttributesAtPath: path traverseLink: (BOOL) flag Gets attributes for file
-(BOOL) changeFileAttributes: attr atPath: path Changes file attributes















Common Path Utility Methods
MethodDescription
+(NSString *) pathWithComponents: components Constructs a valid path from elements in components
-(NSArray *) pathComponents Deconstructs a path into its constituent components
-(NSString *) lastPathComponent Extracts the last component in a path
-(NSString *) pathExtension Extracts the extension from the last component in a path
-(NSString *) stringByAppendingPathComponent: path Adds path to the end of an existing path
-(NSString *) stringByAppendingPathExtension: ext Adds the specified extension to the last component in the path
-(NSString *) stringByDeletingLastPathComponent Removes the last path component
-(NSString *) stringByDeletingPathExtension Removes the extension from the last path component
-(NSString *) stringByExpandingTildeInPath Expands any tildes in the path to the user's home directory (~) or a specified user's home directory (~user)
-(NSString *) stringByResolvingSymlinksInPath Attempts to resolve symbolic links in the path
-(NSString *) stringByStandardizingPath Standardizes a path by attempting to resolve ~, ..(parent directory), .(current directory), and symbolic links



Common Resources Path for iPhone
NSBundle Select all

NSString *myinfoplist = [ [ NSString alloc ] initWithFormat: @"%@/Info.plist", [[NSBundle mainBundle] resourcePath] ];
NSLog (@"Documents Folder is %@",[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"]);
NSString *myFile = [ [ NSString alloc ] initWithFormat: @"%@/Documents/file.db", NSHomeDirectory() ];

NSDirectoryEnumerator *dirEnum;
NSString *file;
dirEnum = [ [ NSFileManager defaultManager ] enumeratorAtPath:NSHomeDirectory()];
while (file = [ dirEnum nextObject ]) {
NSLog(@"%@",[NSHomeDirectory() stringByAppendingPathComponent:file]);
/*
Documents/
Library/
Preferences/
MyApp.app/
*/
}






iPhone Sample Source Code : UISlider UITextField UISwitch & UISegmentedControl



This is a sample source code (no interface builder file) implementing the one similar to Setting Bundle for UIKit Controls
UISlider, UITextField, UISwitch & UISegmentedControl

main.m Select all

// main.m
// Settings
//

#import <UIKit/UIKit.h>

int main(int argc, char *argv[]) {

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
int retVal = UIApplicationMain(argc, argv, nil, @"AppDelegate");
[pool release];
return retVal;
}


AppDelegate.h Select all

// AppDelegate.h
// Settings
//

#import <UIKit/UIKit.h>
#pragma mark -
#pragma mark MainViewController
#pragma mark -

@interface MainViewController : UITableViewController <UITextFieldDelegate>{

UITextField *activeTextField;
}

- (id) init;
- (void) dealloc;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;

@end

#pragma mark -
#pragma mark AppDelegate
#pragma mark -

@interface AppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MainViewController *viewController;
UINavigationController *navigationController;
}

@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) MainViewController *viewController;

@end


AppDelegate.m Select all

// AppDelegate.m
// Settings
//
//

#define DEBUG_BUILD

#ifdef DEBUG_BUILD
#define DEBUGLOG(x) x
#define LogMethod() NSLog(@"%@ %@", self, NSStringFromSelector(_cmd))
#else
#define DEBUGLOG(x)
#define LogMethod()
#endif

#import "AppDelegate.h"

#pragma mark -
#pragma mark MainViewController
#pragma mark -

@implementation MainViewController

- (id) init {
self = [ super initWithStyle: UITableViewStyleGrouped ];

if (self != nil) {
self.title = @"Settings";
}
return self;
}

- (void) loadView {
LogMethod();
[ super loadView ];
}

- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation
{
LogMethod();
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

- (void)didReceiveMemoryWarning {
LogMethod();
[ super didReceiveMemoryWarning ];
}

- (void)dealloc {
// [ shipStabilityControl release ];
[ super dealloc ];
}

#pragma mark - UITableView delegates

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
switch (section) {
case(0):
return 4;
break;
case(1):
return 3;
break;
case(2):
return 1;
break;
}

return 0;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
switch (section) {
case(0):
return @"Game Settings";
break;
case(1):
return @"Advanced Settings";
break;
case(2):
return @"About";
break;
}
return nil;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [ NSString stringWithFormat: @"%d:%d", [ indexPath indexAtPosition: 0 ], [ indexPath indexAtPosition:1 ]];

UITableViewCell *cell = [ tableView dequeueReusableCellWithIdentifier: CellIdentifier];

if (cell == nil) {
cell = [ [ [ UITableViewCell alloc ] initWithFrame: CGRectZero reuseIdentifier: CellIdentifier] autorelease ];

cell.selectionStyle = UITableViewCellSelectionStyleNone;

switch ([ indexPath indexAtPosition: 0]) {
case(0):
switch([ indexPath indexAtPosition: 1]) {
case(0):
{
UISlider *musicVolumeControl = [ [ UISlider alloc ] initWithFrame: CGRectMake(170, 0, 125, 50) ];
musicVolumeControl.minimumValue = 0.0;
musicVolumeControl.maximumValue = 10.0;
musicVolumeControl.tag = 0;
musicVolumeControl.value = 3.5;
musicVolumeControl.continuous = YES;
[musicVolumeControl addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: musicVolumeControl ];
cell.textLabel.text = @"Music Volume"; // OS3
// cell.text = @"Music Volume";
[ musicVolumeControl release ];
}
break;
case(1):
{
UISlider *gameVolumeControl = [ [ UISlider alloc ] initWithFrame: CGRectMake(170, 0, 125, 50) ];
gameVolumeControl.minimumValue = 0.0;
gameVolumeControl.maximumValue = 10.0;
gameVolumeControl.tag = 1;
gameVolumeControl.value = 3.5;
gameVolumeControl.continuous = YES;
[gameVolumeControl addTarget:self action:@selector(sliderAction:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: gameVolumeControl ];
cell.textLabel.text = @"Game Volume"; // OS3
// cell.text = @"Game Volume";
[ gameVolumeControl release ];
}
break;
case(2):
{
UISegmentedControl *difficultyControl = [ [ UISegmentedControl alloc ] initWithFrame: CGRectMake(170, 5, 125, 35) ];
[ difficultyControl insertSegmentWithTitle: @"Easy" atIndex: 0 animated: NO ];
[ difficultyControl insertSegmentWithTitle: @"Hard" atIndex: 1 animated: NO ];
difficultyControl.selectedSegmentIndex = 0;
difficultyControl.tag = 2;
[difficultyControl addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: difficultyControl ];
cell.textLabel.text = @"Difficulty"; // OS3
// cell.text = @"Difficulty";
[difficultyControl release];
}
break;
case(3):
{
UISegmentedControl *actionControl = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects: @"Check", @"Search", @"Tools", nil]];
actionControl.frame = CGRectMake(145, 5, 150, 35);
actionControl.selectedSegmentIndex = 1;
actionControl.tag = 3;
[actionControl addTarget:self action:@selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
actionControl.segmentedControlStyle = UISegmentedControlStyleBar;

[cell addSubview:actionControl];
cell.textLabel.text = @"Actions"; // OS3
// cell.text = @"Actions";
[actionControl release];
}
break;
}
break;
case(1):
switch ([ indexPath indexAtPosition: 1 ]) {
case(0):
{
UITextField *playerTextField = [ [ UITextField alloc ] initWithFrame: CGRectMake(150, 10, 145, 34) ];
playerTextField.adjustsFontSizeToFitWidth = YES;
playerTextField.textColor = [UIColor blackColor];
playerTextField.font = [UIFont systemFontOfSize:17.0];
playerTextField.placeholder = @"";
playerTextField.backgroundColor = [UIColor clearColor];
playerTextField.autocorrectionType = UITextAutocorrectionTypeNo; // no auto correction support
playerTextField.autocapitalizationType = UITextAutocapitalizationTypeNone; // no auto capitalization support
playerTextField.textAlignment = UITextAlignmentRight;
playerTextField.keyboardType = UIKeyboardTypeDefault; // use the default type input method (entire keyboard)
playerTextField.returnKeyType = UIReturnKeyDone;
playerTextField.tag = 0;
playerTextField.delegate = self;

playerTextField.clearButtonMode = UITextFieldViewModeNever; // no clear 'x' button to the right
playerTextField.text = @"";
[ playerTextField setEnabled: YES ];
[ cell addSubview: playerTextField ];
cell.textLabel.text = @"Player"; // OS3
// cell.text = @"Player";
[playerTextField release];
}
break;
case(1):
{
UISwitch *resetControl = [ [ UISwitch alloc ] initWithFrame: CGRectMake(200, 10, 0, 0) ];
resetControl.on = YES;
resetControl.tag = 1;
[resetControl addTarget:self action:@selector(switchAction:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: resetControl ];
cell.textLabel.text = @"Reset"; // OS3
// cell.text = @"Reset";
[resetControl release];
}
break;
case(2):
{
UISwitch *debugControl = [ [ UISwitch alloc ] initWithFrame: CGRectMake(200, 10, 0, 0) ];
debugControl.on = NO;
debugControl.tag = 2;
[debugControl addTarget:self action:@selector(switchAction:) forControlEvents:UIControlEventValueChanged];
[ cell addSubview: debugControl ];
cell.textLabel.text = @"Debug"; // OS3
// cell.text = @"Debug";
[debugControl release];
}
break;
}
break;
case(2):
{
UITextField *versionControl = [ [ UITextField alloc ] initWithFrame: CGRectMake(170, 10, 125, 38) ];
versionControl.text = @"1.0.0 Rev. B";
[ cell addSubview: versionControl ];

[ versionControl setEnabled: YES ];
versionControl.tag = 2;
versionControl.delegate = self;
cell.textLabel.text = @"Version"; // OS3
// cell.text = @"Version";
[versionControl release];
}
break;
}
}

return cell;
}

#pragma mark ControlEventTarget Actions


- (void)segmentAction:(UISegmentedControl*)sender
{
if ([activeTextField canResignFirstResponder])
[activeTextField resignFirstResponder];

DEBUGLOG(NSLog(@"segmentAction: sender = %d, segment = %d", [sender tag], [sender selectedSegmentIndex]));
}

- (void)sliderAction:(UISlider*)sender
{
if ([activeTextField canResignFirstResponder])
[activeTextField resignFirstResponder];
DEBUGLOG(NSLog(@"sliderAction: sender = %d, value = %.1f", [sender tag], [sender value]));
}

- (void)switchAction:(UISwitch*)sender
{
if ([activeTextField canResignFirstResponder])
[activeTextField resignFirstResponder];
DEBUGLOG(NSLog(@"switchAction: sender = %d, isOn %d", [sender tag], [sender isOn]));
}


#pragma mark <UITextFieldDelegate> Methods

- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
activeTextField = textField;
DEBUGLOG(NSLog(@"textFieldShouldBeginEditing: sender = %d, %@", [textField tag], [textField text]));
return YES;
}

- (void)textFieldDidEndEditing:(UITextField *)textField
{
DEBUGLOG(NSLog(@"textFieldDidEndEditing: sender = %d, %@", [textField tag], [textField text]));
}

- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
DEBUGLOG(NSLog(@"textFieldShouldReturn: sender = %d, %@", [textField tag], [textField text]));
activeTextField = nil;
[textField resignFirstResponder];
return YES;
}


@end

#pragma mark -
#pragma mark AppDelegate
#pragma mark -

@implementation AppDelegate

@synthesize window;
@synthesize viewController;

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
LogMethod();

// If you want the status bar to be hidden at launch use this:
// application.statusBarHidden = YES;
//
// To set the status bar as black, use the following:
// application.statusBarStyle = UIStatusBarStyleBlackOpaque;


// Create window
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

// this helps in debugging, so that you know "exactly" where your views are placed;
// if you see "red", you are looking at the bare window, otherwise use black
// window.backgroundColor = [UIColor redColor];

viewController = [ [ MainViewController alloc ] init ];

navigationController = [ [ UINavigationController alloc ] initWithRootViewController: viewController ];

/* Anchor the view to the window */
[window addSubview:[navigationController view]];

/* Make the window key and visible */
[window makeKeyAndVisible];
}

- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
{
// low on memory: do whatever you can to reduce your memory foot print here
}


- (void)dealloc
{
[viewController release];
[navigationController release];
[window release];
[super dealloc];
}

@end