0

Auto-incrementing Build Numbers in Xcode

-

Users and testers will find bugs you are sure you have already fixed. Sometimes they use the wrong version, sometimes your fix is not as good as you thought. Either way a tiny unique version number visible in the app can save you hours of work.

Incrementing the version number of your project for every small update is often not feasible, if it involves manual labor it just does not get done. Would it not be nice if Xcode just autoincremented a build number for you every time you build?

This can be done

There are dozens of solution to the problem available by Google. Unfortunately most do not work in both Xcode 3.2 and Xcode 4, and many more require a lot of hacking, even running external Perl or Python scripts. Using avgtool seems to be a major overkill for most use-cases. There must be an easier way, and there is.

What we want to do is to have the build number available in our Info.plist file, so that it can be read and displayed at run-time. And we also want Xcode to automatically increment this number for every build.

Add a key named CWBuildNumber to your Info.plist file, and set it to a sane start value, maybe "0". You can load it at run-time with a short statement like:

  1. NSString* buildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CWBuildNumber"];
NSString* buildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CWBuildNumber"];


Both Xcode 3.2 and Xcode 4 allows to add a Run Script phase to any target. Unfortunately Xcode 3.2 and 4 run these scripts with different paths. PROJECT_DIR environment variable to the rescue! Secondly we want to rewrite the target's source Info.plist file, not the file bundled with the application, so make sure to order the script phase before the Copy Resources phase. Then just add this tiny script phase to your target build:

  1. buildNumber=$(/usr/libexec/PlistBuddy -c "Print CWBuildNumber" ${PROJECT_DIR}/MyApp-Info.plist)
  2. buildNumber=$(($buildNumber + 1))
  3. /usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${PROJECT_DIR}/MyApp-Info.plist
buildNumber=$(/usr/libexec/PlistBuddy -c "Print CWBuildNumber" ${PROJECT_DIR}/MyApp-Info.plist)
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${PROJECT_DIR}/MyApp-Info.plist


Conclusions

Happy developers, and happy tester. Maybe even happy users, if you choose to show the full version number including build number in the final product.

PS:

Make file build.plist with CWBuildNumber key int project root folder.

Add a key named CWBuildNumber to your Info.plist file, and set it to a sane start value, maybe "0".

 

Add to Build->pre-actions
 

  1. infoplist="$PROJECT_DIR/${INFOPLIST_FILE}"
  2. buildplist="$PROJECT_DIR/build.plist"
  3.  
  4. # echo "Info.plist = $infoplist \n Build.plist = $buildplist" > ${PROJECT_DIR}/log.txt
  5.  
  6. buildNumber=$(/usr/libexec/PlistBuddy -c "Print CWBuildNumber" ${buildplist})
  7. buildNumber=$(($buildNumber + 1))
  8. /usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${buildplist}
  9. /usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${infoplist}
infoplist="$PROJECT_DIR/${INFOPLIST_FILE}"
buildplist="$PROJECT_DIR/build.plist"

# echo "Info.plist = $infoplist \n Build.plist = $buildplist" > ${PROJECT_DIR}/log.txt

buildNumber=$(/usr/libexec/PlistBuddy -c "Print CWBuildNumber" ${buildplist})
buildNumber=$(($buildNumber + 1))
/usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${buildplist}
/usr/libexec/PlistBuddy -c "Set :CWBuildNumber $buildNumber" ${infoplist}
0

Xcode 4 : Debug Breakpoints, Conditions and Actions

-

I recently bumped into a few new debugging features in Xcode 4 while looking at breakpoint options. To show how this works, let’s look at a small block of code where I’ve already set a breakpoint by clicking in the margin area on the left side in the editor:

With a breakpoint set, right click (or control-click) on the breakpoint indicator, the blue area shown below in the screenshot below:

The popup dialog below will be shown, select Edit Breakpoint:

At this point you will be shown the dialog below. I configured the settings to only trigger the breakpoint if the value of counter is > 2. When this occurs, a message will be spoken that indicates the breakpoint name and hit count (how many times the breakpoint has been activated).

The above is just one of many options for triggering and configuring breakpoint settings. When you get a chance, I recommend you take a few minutes to get familiar with the options for managing breakpoints. And who knows, the voice response may come in handy for those times when you are looking crossed-eyed at the screen from endless hours of coding…

0

Using your iOS 5 device with Xcode 4.1

-

To enable iOS 5 support in Xcode 4.1, read on.

You've upgraded one or more devices to iOS 5.0 and try to use Xcode 4.1, only to be told it doesn't recognize the version of the OS.  Why would you care?  Apple has been advising for some time that gcc is going away, and that date may be fast approaching.  Unfortunately, Clang / llvm lack some features available in gcc, such as register assigned local or global variables.  We've only just gained access to a version of Clang that supports C++, and so you may still need some time to migrate your code.

Assuming Xcode 4.1 is in /Developer and Xcode 4.2 is in /Xcode42, run the following, substituting the appropriate iOS 5 build numbers:

cd /Developer/Platforms/iPhoneOS.platform/DeviceSupport
ln -s /Xcode42/Platforms/iPhoneOS.platform/DeviceSupport/5.0\ \(9A5313e\)/ 5.0\ \(9A5213e\)
0

PaperStack Alpha Source Code

-

Hello, after iOS 5 release (introducing PageViewController and Book Applications) PaperStack team decided to convert the "Books" project in something more interesting and portable.

Anyway, we decided to release our alpha source code to reveal the geometry and math behind the Page Curl filter to everyone. Hope this helps!

1

Determine MAC Address

-

The MAC (Media Access Control) address is an identifier that is associated with a network adapter and uniquely identifies a device on a network. A MAC address consists of 12 hexadecimal numbers, typically formatted as follows

XX:XX:XX:YY:YY:YY

The XX values in a MAC address identify the manufacturer, the YY values are the serial number assigned to the network adapter.

The MAC address can be useful if you need a way to uniquely identify a device – this can be used as a substitute for the UDID value that is now deprecated in iOS 5 and greater.

The code below shows how to get the MAC address on an iOS device:

  1. #include <sys/socket.h>
  2. #include <sys/sysctl.h>
  3. #include <net/if.h>
  4. #include <net/if_dl.h>
  5.  
  6. - (NSString *)getMacAddress
  7. {
  8. int mgmtInfoBase[6];
  9. char *msgBuffer = NULL;
  10. NSString *errorFlag = NULL;
  11. size_t length;
  12.  
  13. // Setup the management Information Base (mib)
  14. mgmtInfoBase[0] = CTL_NET; // Request network subsystem
  15. mgmtInfoBase[1] = AF_ROUTE; // Routing table info
  16. mgmtInfoBase[2] = 0;
  17. mgmtInfoBase[3] = AF_LINK; // Request link layer information
  18. mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces
  19.  
  20. // With all configured interfaces requested, get handle index
  21. if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
  22. errorFlag = @"if_nametoindex failure";
  23. // Get the size of the data available (store in len)
  24. else if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
  25. errorFlag = @"sysctl mgmtInfoBase failure";
  26. // Alloc memory based on above call
  27. else if ((msgBuffer = malloc(length)) == NULL)
  28. errorFlag = @"buffer allocation failure";
  29. // Get system information, store in buffer
  30. else if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
  31. {
  32. free(msgBuffer);
  33. errorFlag = @"sysctl msgBuffer failure";
  34. }
  35. else
  36. {
  37. // Map msgbuffer to interface message structure
  38. struct if_msghdr *interfaceMsgStruct = (struct if_msghdr *) msgBuffer;
  39.  
  40. // Map to link-level socket structure
  41. struct sockaddr_dl *socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);
  42.  
  43. // Copy link layer address data in socket structure to an array
  44. unsigned char macAddress[6];
  45. memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);
  46.  
  47. // Read from char array into a string object, into traditional Mac address format
  48. NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
  49. macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]];
  50. NSLog(@"Mac Address: %@", macAddressString);
  51.  
  52. // Release the buffer memory
  53. free(msgBuffer);
  54.  
  55. return macAddressString;
  56. }
  57.  
  58. // Error...
  59. NSLog(@"Error: %@", errorFlag);
  60.  
  61. return errorFlag;
  62. }
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <net/if.h>
#include <net/if_dl.h>

- (NSString *)getMacAddress
{
int mgmtInfoBase[6];
char *msgBuffer = NULL;
NSString *errorFlag = NULL;
size_t length;

// Setup the management Information Base (mib)
mgmtInfoBase[0] = CTL_NET; // Request network subsystem
mgmtInfoBase[1] = AF_ROUTE; // Routing table info
mgmtInfoBase[2] = 0;
mgmtInfoBase[3] = AF_LINK; // Request link layer information
mgmtInfoBase[4] = NET_RT_IFLIST; // Request all configured interfaces

// With all configured interfaces requested, get handle index
if ((mgmtInfoBase[5] = if_nametoindex("en0")) == 0)
errorFlag = @"if_nametoindex failure";
// Get the size of the data available (store in len)
else if (sysctl(mgmtInfoBase, 6, NULL, &length, NULL, 0) < 0)
errorFlag = @"sysctl mgmtInfoBase failure";
// Alloc memory based on above call
else if ((msgBuffer = malloc(length)) == NULL)
errorFlag = @"buffer allocation failure";
// Get system information, store in buffer
else if (sysctl(mgmtInfoBase, 6, msgBuffer, &length, NULL, 0) < 0)
{
free(msgBuffer);
errorFlag = @"sysctl msgBuffer failure";
}
else
{
// Map msgbuffer to interface message structure
struct if_msghdr *interfaceMsgStruct = (struct if_msghdr *) msgBuffer;

// Map to link-level socket structure
struct sockaddr_dl *socketStruct = (struct sockaddr_dl *) (interfaceMsgStruct + 1);

// Copy link layer address data in socket structure to an array
unsigned char macAddress[6];
memcpy(&macAddress, socketStruct->sdl_data + socketStruct->sdl_nlen, 6);

// Read from char array into a string object, into traditional Mac address format
NSString *macAddressString = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
macAddress[0], macAddress[1], macAddress[2], macAddress[3], macAddress[4], macAddress[5]];
NSLog(@"Mac Address: %@", macAddressString);

// Release the buffer memory
free(msgBuffer);

return macAddressString;
}

// Error...
NSLog(@"Error: %@", errorFlag);

return errorFlag;
}

The output will look as follows: Mac Address: E0:F8:47:C0:E3:C9

 

UPD: Update code to fixed version. Thx to C?ur

1

Simple Sqlite Database Interaction Using FMDB

-

Introduction

In the age where Core Data is king, the database that started it all is often overlooked. I’m talking of course about sqlite. As you may or may not know, prior to core data, sqlite was the preferred method of storing relational data on iOS devices.

Although, most developers don’t interact with sqlite directly, they still use it under the hood as the primary data store for core data. This is great and all, but there are often times when raw sqlite is still the preferred storage method.

A few of these might include:

  • Caching
  • Preferences
  • Simple objects
  • Portability
  • Cross platform applications

Recently, I have had to make heave use of raw sqlite as a caching strategy in a new project that I’m working on. Being that we are developing a framework for other developers to include in their projects, we can’t always assume that they have their environment set up to use core data. When I was but a n00b iOS developer I did all of the crazy sqlite management by hand. See This post series, but don’t spend too much time there because it’s embarrassing.

Gross right? Now, there is a much easier way to manage and interact with your sqlite databases. This library has been around for quite some time and I wish I had known about it earyly on.

(more...)

« 1 ... 27 28 29 30 31 32 33 34 35 36 37 38 »