Posts in Technology (100)

Our first adventure with Windows Phone: Porting Bible Promises

For mobile app developers, it's been a two-horse race up to now: iOS versus Android. We've been keeping an eye on the progress of Windows Phone, and there are finally signs that it may be solidifying it's position in third place, it's edged up to a 3.7% market share worldwide according to a recent survey.

The time seemed right to dip our toes into the Windows Phone ecosystem, so we decided to port one of our existing apps, Bible Promises, to Windows Phone. Why choose Bible Promises? First, Bible Promises has a large community of active users on Facebook, Twitter, Pinterest and Tumblr. Second, as a content-based app rather than a game, it would allow us to explore the native UI elements provided by Windows Phone.

Our first step was to identify a mininum viable feature set. Bible Promises for iOS and Android are both mature products which have gained a lot of features over the year. We didn't necessarily need to port everything over on the first version. In Basecamp, we brainstormed on the most important features:

Screen Shot 2013-08-09 at 11.28.48

We also decided which features we should include that would make the app work well in the Windows Phone environment. At the Bibletech conference earlier this year, I spoke with Matthias Shapiro, a Windows Phone evangelist, and asked him one one feature he would add to an app to make it feel native on Windows Phone. He recommended adding a Live Tile. We decided to use the Live Tile to promote the Daily Verse, one of the most popular features of our iPhone and Android apps.

wp_ss_20130422_0001

The next step was to get our development environment set up. This was a little painful: we're used to working on our Mac laptops, so had to resurrect an older PC, install Windows 8 on it, and then install Visual Studio Express. Despite a lot of messing about with settings, we weren't able to get the Windows Phone Emulator to work, so all of our testing had to happen on a device.

For a device, we purchased the excellent value Huawei Ascend W1 from Taobao. We had no problem getting this registered as a development device and running our apps on it.

For the app UI, we decided to follow the Windows Phone design guidelines as much as possible. This meant that the app has a distinctive feeling from our iOS and Android apps. We used the Panorama control to allow the user to swipe between verses. To ensure that the app still "felt" like Bible Promises, we carried over the colors and fonts from our existing apps, such as using Georgia as the main font. This ensured the final app felt like a Windows Phone app, but was still familiar as Bible Promises.

1

2

Finally, we submitted to the Windows Store! The app is now available to download. There's a trial version which allows you to sample the first half of the category list, the full version is just $0.99 or equivalent.

We'd love to hear your feedback if you have a Windows Phone. Please get in touch!

Debugging retain cycles in Objective-C: four likely culprits

Your iPhone app seems to be working fine. But suddenly, it starts to run slow and crashes! You suspect it's memory-related. Here's how to track down and fix issues with retain cycles, which can cause memory not to be released properly.

I'm assuming you are using ARC and iOS5.0+. While ARC simplifies a lot of memory management, it won't spot all retain cycles for you!

First, check you're genuinely dealing with a memory condition. Try to reproduce the crash on a device, and look for crash reports using Xcode > Organiser > Device Logs.

Low memory crashes don't look like normal crash reports, you won't see a stack trace! Instead you'll probably just see Process = Unknown, and the crash report will contain a list of processes which were running at the time of the crash.

Screen Shot 2013-04-16 at 14.01.59

In this example, you can see that Biblegram was using over 25000 pages of memory. 1 page of memory is 4KB, so that's 100MB of memory, which seems much too high.

Next, fire up Instruments via Product > Profile and select the "Allocations" template. Playing around with the app, you should easily be able to locate places where the memory allocation keeps going up and up.

Screen Shot 2013-04-16 at 14.12.13

This "staircase" pattern is a giveaway. I'm repeatedly pushing and popping one view controller, but the memory goes up and up.

Try putting a breakpoint in the dealloc method of the problematic view controller. Most likely, this will never get hit, showing that the view controller is never released.

Screen Shot 2013-04-16 at 14.30.22

This is a strong indication that we have a retain cycle. When the view controller is dismissed there are still some strong references to it, so it doesn't get dealloced.

As one last verification, enter the name of the class into the search box in the top right of Instruments, and check the "# living" column. This is showing 3, when we'd expect it to show 1.

Screen Shot 2013-04-16 at 14.15.38

You can drill down into the instances of the view controller by tapping the small arrow to the right of the class name, and drill down further to see every place that the view controller is retained and released.

This view can be rather overwhelming: the system frameworks do a lot of retaining and releasing on your behalf! For example, instantiating a NIB can easily increase the retain count to 40 temporarily.

So: here are four common errors to look out for that may cause your retain count to be higher than expected.

1. NSTimer

If you create an NSTimer object on a view controller, be sure that invalidate is called on it when dismissing the view controller, otherwise it will retain self.

2. Observers/NSNotificationCenter

If you add an observer to NSNotificationCenter, make sure you remove all observers when dismissing the view controller, otherwise they will retain self.

3. Blocks

You should not call [self doSomething] from inside a block, this can easily lead to the block capturing a reference to self. Instead, make a weak reference to self:

BAD:

  1.  
  2. dispatch_async(queue, ^{
  3. [self doSomething];
  4. });
  5.  

GOOD

  1.  
  2. __weak MyViewController *safeSelf = self;
  3. dispatch_async(queue, ^{
  4. [safeSelf doSomething];
  5. });
  6.  

4. Delegates

if you use

  1.  
  2. someObj.delegate = self;
  3.  

inside the view controller, check the delegate property on someObj is weak.

  1.  
  2. @property (nonatomic, weak) id delegate;
  3.  

Once you've made your fixes, check that dealloc is getting hit and the allocations no longer increase endlessly.

Controlling a 10-bit Digital Potentiometer via SPI with Arduino

1. A brief introduction to the Serial Peripheral Interface (SPI)

The Serial Peripheral Interface a.k.a SPI or four-wire serial interface is a full-duplex serial data protocol used by microcontrollers for communicating with one or more peripheral devices. Devices communicate in master/slave mode and there are four logic signals:

  • - MOSI: Master Out Slave In, is the master line to send data to the peripheral.
  • - MISO: Master In Slave Out, is the slave line to send data to the master.
  • - SCK: Serial Clock, the clock pulses which synchronize data transmission generated by the master.
  • - SS: Slave Select, the pin on each device that the master can use to enable and disable specific devices.

For more on this topic, visit Wikipedia's page on SPI.

2. Wiring the Master - Slave

For this tutorial we will use the Non-volatile memory, 1024 Position (10-bit) Digital Potentiometer AD5131 from Analog Devices. Wiring the IC to Arduino should be pretty straight-forward by looking at the pin configuration from the Data Sheet.

You might encounter different naming conventions for the lines on the SPI interface; the most commonly used are:

  • - The Motorola terms: MOSI and MISO for 'Master Out Slave In' and 'Master In Slave Out'.
  • - The PIC terms: SDI and SDO for 'SPI Data In' and 'SPI Data Out'.

MOSI always connects to MOSI or SDI (slave) and MISO always connects MISO or SDO (slave). CLK or SCK both refer to the serial clock and SS (slave select) or CS (chip select) are the same line.

On the Arduino Uno or Duemilanove the SPI lines are available from the digital pins 11 (MOSI), 12 (MISO) and 13 (SCK). Also, MOSI, MISO and SCK are available in a consistent physical location on the ICSP header.

If you are using a different Arduino board, the SPI lines might be located on different pins numbers. To find this information, please go to the SPI Library reference on the Arduino website.  Please note that when using the SPI feature on the Arduino, the digital pins 11, 12 and 13 can't be used as digital I/O.

Now, let's take a look at our wiring schematic.

Note that, as in this example we are not using all the features from the AD5231.  We left some of the pins unconnected (O1, O2 and RDY). Also, the pins marked with the optional features Write Protect (WP) and Hardware Override (PR) should be connected to VDD if they are not used.

3. Basic Operation

The AD5231 Digital Potentiometer is designed to operate as a true variable resistor replacement device for analog signals. The digital potentiometer wiper position is determined by the RDAC register contents (Address 0x0). The RDAC register acts as a scratchpad register, allowing as many values changes as necessary to place the potentiometer wiper in the correct position.

The basic mode of setting the variable resistor wiper position (programming the scratchpad register) is accomplished by loading the serial data input register with the instruction: 0xB, Address 0x0, and the desired wiper position data.

4. Serial Data Interface

The AD5231 uses a 24-bit serial data-word loaded Most Significant Bit first (MSBFIRST). The CS (chip select) pin must be held LOW until the complete data-word is loaded into the SDI pin. When CS returns to HIGH, the serial data-word is decoded. The command bits (Cx) control the operation of the digital potentiometer. The address bits (Ax) determine which register is activated. The data bits (Dx) are the values that are loaded into the decoded register.

 

MSB | Command Byte 0
Data Byte 1
Data Byte 0 | LSB
C3 C2 C1 C0 Ax Ax Ax Ax
X X X X X X D9 D8
D7 D6 D5 D4 D3 D2 D1 D0

5. Programing the Interface with Arduino

The Arduino SPI library allows us to transfer [SPI.transfer(byte)] only 8-bits (1 byte) at a time. In order to transfer a complete instruction (24-bits) to the digital potentiometer we will have to send the instruction in 3 parts of 8-bits each.

The first byte or 'Command Byte' is composed by the Command + Address which allows us to write data into the RDAC register:

Command = 0xB = 1011
Address = 0x0 = 0000
then:
Command + Address = 10110000

The following 2 bytes, the Data Bytes, contain the 10-bits (from 0 to 1023) wiper position. The Data Byte 1 only contains 2 bits from this value and 6 bits that are not used (X). In order to achieve this operation we will use the bitwise operands Logical Right Shift '>>' and AND '&'.

If you are not familiar with bitwise operations, I suggest reading  the 'Absolute Beginner's Guide to Bit Shifting' post from StackOverflow.

For this example, we will assume that we want to send the value 620 to the digital potentiometer to move the Wiper W to approximately 60%  full-scale position, then:

620 = 0000001001101100
620 >> 8 = 00000010 //Shifting 8 bits to the right
620 & 11111111 = 01101100  //Truncate to 8-bits on the LSB side

And finally, the Arduino code.

#include <SPI.h> 

const int csPin = 10;

void setup() {

 SPI.begin();
 SPI.setBitOrder(MSBFIRST); //We know this from the Data Sheet

 pinMode(csPin,OUTPUT);
 digitalWrite(csPin, HIGH);
}

void loop() {
 for(int i=0; i<1023; i++) { 
  digitalPotWrite(0,i);
  delay(10);
 } 
}

void digitalPotWrite(int address, int value) {
 digitalWrite(csPin, LOW); //select slave
 byte command = 0xB0; //0xB0 = 10110000 
 command += address; 
 SPI.transfer(command); 
 byte byte1 = (value >> 8);
 byte byte0 = (value & 0xFF); //0xFF = B11111111
 SPI.transfer(byte1);
 SPI.transfer(byte0);
 digitalWrite(csPin, HIGH); //de-select slave
}

There are much more features available in the AD5231 such as memory storing and restoring, increment/decrement, ±6 dB/step log taper adjustment, wiper setting read-back and extra EEMEM  for user-defined information, that are not covered in this post.

ReignDesign’s most popular blog posts of 2012

ReignDesign had a fun and exciting year! We released some apps, visited conferences and  contemplated new technology! Here's a Top Ten List of our biggest moments.

1. Oooohh, look at the pretty pictures, iPad Retina vs. Non-retina. We loved the clarity of the retina display. How did we ever live without it?
2.  Git and SCP: this tutorial is perfect if you can't find your USB stick or if you don't feel like walking across the room to find one.
3.  Ever wondered about the controls for touchscreen games? Watch this talk that founder, Matt Mayer, gave in Kiev.
4.  In iOS5, Apple introduced native Twitter integration via the "Tweet Sheet" (aka TWTweetComposeViewController), allowing you to easily implement Twitter in your iOS app without worrying about all the heavy lifting. Continue reading this tutorial for more details.
5.  Look At Teh Pritee Kittehs! Our app, Cat Scan, was fun to make, and we enjoyed turning all of our phone contacts into cute kittens.
6.  Adding labels and re-assigning Github issues: Two ways to automate this common task!
7. Making Flockwork was a great learning experience filled with a few technical hurdles. We wrote a series of blog posts explaining the challenges in cocos2d.
8. Controls for games are important....like, really important.
9. Almost a year ago, we wondered how to best design an app for Windows 8  How accurate were we?
10. Remember the trend of making videos and lists about Sh*t People Say/Do, etc? We made one for iPhone Developers. You're welcome.
ReignDesign is excited about 2013, and we are looking forward to creating and updating.
Happy New Year!

How to launch Google Maps or Apple Maps from an iOS app

Today Google announced their much-anticipated Google Maps app for iOS. They also plan to make available a Google Maps SDK for iOS allowing iOS developers to integrate Google Maps in their apps, however at present API keys are only available for selected developers.

If you want to provide your app's users with the ability to open a location in Google Maps, there is an option which works today: Google have added a comgooglemaps URL scheme to their app so third-party apps can launch the Google Maps app.

Assuming you'd like to give your users a choice of opening a location in both Apple or Google maps, you can set up some code like this in a new view controller:

  1. #import "ViewController.h"
  2. #import <MapKit/MapKit.h>
  3.  
  4. @implementation ViewController
  5.  
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9. // Add a button to pop open an action sheet
  10. UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
  11. btn.frame = CGRectMake(80,100,160,50);
  12. [btn setTitle:@"Open placemark" forState:UIControlStateNormal];
  13. [btn addTarget:self action:@selector(openActionSheet:) forControlEvents:UIControlEventTouchUpInside];
  14. [self.view addSubview:btn];
  15.  
  16. }
  17. -(void)openActionSheet:(id)sender {
  18. //give the user a choice of Apple or Google Maps
  19. UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Open in Maps" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:@"Apple Maps",@"Google Maps", nil];
  20. [sheet showInView:self.view];
  21. }
  22. -(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
  23. //coordinates for the place we want to display
  24. CLLocationCoordinate2D rdOfficeLocation = CLLocationCoordinate2DMake(31.20691,121.477847);
  25. if (buttonIndex==0) {
  26. //Apple Maps, using the MKMapItem class
  27. MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:rdOfficeLocation addressDictionary:nil];
  28. MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placemark];
  29. item.name = @"ReignDesign Office";
  30. [item openInMapsWithLaunchOptions:nil];
  31. } else if (buttonIndex==1) {
  32. //Google Maps
  33. //construct a URL using the comgooglemaps schema
  34. NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"comgooglemaps://?center=%f,%f",rdOfficeLocation.latitude,rdOfficeLocation.longitude]];
  35. if (![[UIApplication sharedApplication] canOpenURL:url]) {
  36. NSLog(@"Google Maps app is not installed");
  37. //left as an exercise for the reader: open the Google Maps mobile website instead!
  38. } else {
  39. [[UIApplication sharedApplication] openURL:url];
  40. }
  41. }
  42. }
  43. @end

Here's the app in action, example code is on Github.

    

For more details, see the Google Maps URL Scheme documentation.