29 Apr 2012

Memory leaks in Instruments after converting to ARC

I decided to convert a project which was mostly fine in terms of memory management to use ARC. After the converstion I wanted to check that everything is fine in Instruments and I couldn't believe what I saw. Virtually everything was leaking! But why? In some of the classes I even set breakpoints inside init and dealloc methods and counted how many times do things get created and deallocated. That seemed to be just fine. Where was the problem than?

The debug build I was running in the simulator was indeed perfecly fine. However the build Instruments were using apparently didn't have ARC enabled and hence everything was leaking.

If you encounter a similar problem go to the build setting of the target that's causing the problems and check the highlighted setting to be all set to yes. In my case the green flags were just fine, set to -fobjc-arc indicating ARC should be on. However the red ones were not for the release build and that is what caused all the problems. After changing everything to YES memory leaks disappeared.

Compiler settings

1 Oct 2011

Playing music in your app - MediaPlayer tutorial

In this tutorial we will have a look at how to use MediaPlayer framework to play music from your app. To begin with we need to#import <MediaPlayer/MediaPlayer.h>. There are three core classes that we will work with.

MPMusicPlayerController
There are two types of MPMusicPlayerController

  • Application music player ([MPMusicPlayerController applicationMusicPlayer]) that plays music just in your app and does not affect the in-built iPod
  • iPod music player ([MPMusicPlayerController iPodMusicPlayer]) that employs the in-built iPod to play music - the music can be controlled in the iPod app and remains playing even after you quit your app

MPMusicPlayerController methods are quite self-explanatory:

  • - setQueueWithQuery: and - setQueueWithItemCollection are used to set playback queue with query (see below)
  • - play, - pause, - stop, - beginSeekingForward, - beginSeekingBackward, - endSeeking, - skipToNextItem, - skipToPreviousItem, - skipToBeginning are all used to control the player
  • currentPlaybackTime, nowPlayingItem, playbackState, repeatMode, shuffleMode, volume are all properties of the player that you can use to change the behavior or display different attributes

MPMediaItem
MPMediaItem is a single item in the media library (such as one song). It is the nowPlayingItem property of the player. Each item has metadata associated with it, those can be accessed by calling valueForProperty: method. The full list of properties can be found in thedocumentation but some examples include MPMediaItemPropertyTitle or MPMediaItemPropertyArtist.

MPMediaQuery
MPMediaQuery is used to do queries in the iPod library. Again, the full description is best to be found in the documentation but a little example demonstrates how MPMediaQuery works.

MPMediaQuery* query = [MPMediaQuery songsQuery]; 
[query addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:@"The Beatles" forProperty:MPMediaItemPropertyArtist comparisonType:MPMediaPredicateComparisonEqualTo]]; 
[query setGroupingType:MPMediaGroupingAlbum];

This creates a query that selects all songs whose artist is "The Beatles" and groups them by album. All the songs in the query can be passed to MPMusicPlayerController to play.

Example
Now put it all together:

//Create an instance of MPMusicPlayerController 
MPMusicPlayerController* myPlayer = [MPMusicPlayerController iPodMusicPlayer]; 
 
//Create a query that will return all songs by The Beatles grouped by album 
MPMediaQuery* query = [MPMediaQuery songsQuery]; 
[query addFilterPredicate:[MPMediaPropertyPredicate predicateWithValue:@"The Beatles" forProperty:MPMediaItemPropertyArtist comparisonType:MPMediaPredicateComparisonEqualTo]]; 
[query setGroupingType:MPMediaGroupingAlbum]; 

//Pass the query to the player 
[myPlayer setQueueWithQuery:query]; 

//Start playing and set a label text to the name and image to the cover art of the song that is playing 
[myPlayer play]; 
someLabel.text = [myPlayer.nowPlayingItem valueForProperty:MPMediaItemPropertyTitle]; 
someImageView.image = [myPlayer.nowPlayingItem valueForProperty:MPMediaItemPropertyArtwork]; 

 

22 Sep 2011

RawApps iPhone WordPress theme gets a redesign

Today I did a little redesign of RawApps WordPress theme for iPhone apps. I've removed all the pictures that were used to create background and looked, well... not so well. Now the background is just plain colour and the tabs for pages were replaced by a simple bar. Here it's what it looks like now (the bottom with widgets isn't shows, doesn't fit onto 13" screen).

I'll be working on adding a few more colour schemes to choose from and potentially even enabling custom colours. Should you have any comments on the design or what would you like to see in the future feel free to comment!

PS: You can find the project on GitHub.

16 Sep 2011

Free WordPress theme for showcasing iPhone apps

As you may remember some time ago I discovered a great way of showcasing apps for any iPhone dev working on low budget - a free WordPress theme. Unfortunatelly there is only one of these available online from great guys at RawApps and it has not been updated for some time. After a few emails with them, they set up a GitHub repo to continue the development of the theme.

How to set this up
First you will need WordPress downloaded and installed on your server. To do this follow the steps provided by WordPress, it shouldn't be hard. Once you download the theme, you need to copy it into /wp-content/themes directory and enable it in your WP admin panel under Settings->Themes. Set up the name, price, pictures and... you're done, enjoy! A nice website for your app is up and running.

Screenshot

Want to participate?
As you may have noted this theme is not yet up-to-date and does need some improvements. If you'd like to participate in the development, you're strongly encouraged to do so and your time and effort will be highly appreciated by fellow devs. To do this just fork it on GitHub and use pull requests to submit changes.

1 Aug 2011

Conforming to NSCopying - making copies of your custom class objects

The NSCopying protocol declares a method for providing functional copies of an object. The exact meaning of “copy” can vary from class to class, but a copy must be a functionally independent object with values identical to the original at the time the copy was made. The difference that needs to be understood is that if you do the following

ABClass* somePointer = [[ABClass alloc] init]; 
ABClass* someOtherPointer; 
someOtherPointer = somePointer;

they will both point to the same place in memory, the same object.

To make a copy (to take an object and copy it to another place in memory) the class must conform to the NSCoding protocol. This protocol requires just one method, copyWithZone: to be implemented. All this method needs to do is to initialize a new instance of the same class, set all its variables to appropriate values and return it.

-(id) copyWithZone:(NSZone *)zone {
     ABClass* newInstance = [[[self class] allocWithZone:zone] init];
     newInstance.property = self.property;
     newInstance.someOtherProperty = self.someOtherProperty;
     return newInstace; }

Now you can make copies like this:

ABClass* somePointer = [[ABClass alloc] init]; 
ABClass* someOtherPointer; 
someOtherPointer = [somePointer mutableCopy];
 

22 Jul 2011

Two simple tricks with CABasicAnimation that make your app look better

Today I was browsing through my snippets in CodeBox (by the way - great app for anybody who works with code, saves a lot of time and work, get it here) and I came accross two simple snippets for animating objects using CABasicAnimation that can enhance an app in a great way if used right so I thought I'll share with you.

To begin with you need to add QuartzCore framework to your project. First snippet is animation that moves an element (UIView, UIWhatever...) along the x or y axis and it goes like this.

//Create a CABasicAnimation object
CABasicAnimation *move = [CABasicAnimation animationWithKeyPath:@"transform.translation.y" ];
[move setFromValue:[NSNumber numberWithFloat:0.0f]];
[move setToValue:[NSNumber numberWithFloat:100.0f]];
[move setDuration:0.3f];
//Add animation to a specific element's layer. Must be called after the element is displayed.
[[element layer] addAnimation:move forKey:@"transform.translation.y"];

Second snippet is a fade transition for whatever UI element.

//Create a CABasicAnimation object. Must be added to the element after it is displayed
CATransition *animation = [CATransition animation];
animation.duration = 1.0;
animation.type = kCATransitionFade;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[myLabel.layer addAnimation:animation forKey:@"changeTextTransition"];

// Change the text and the animation will ocur
myLabel.text = @"Changed text";

There are couple of other options but honestly, do you need to rotate anything in your app? Adding those two kinds of animations makes your app feel much better and provide subtle feedback to the user. But always remeber that even for animation "less is more" is true and too much animation will ruin everything.

15 Jul 2011

iOS Bluetooth development tutorial - using GameKit to connect two iPhones

After working with Bluetooth using GameKit framework for a while in my current project I decided to write a basic tutorial that should help anybody to get started with connecting two iOS devices together. First let's talk about why and when should you use Bluetooth. When I came up with the idea of an app that requires two devices to communicate I had to make a choice of technology that will connect the devices. First thing that came to my mind was to use the Bump API. Why? Because the bumping idea is actually pretty cool + everything is set up for you and you can send data between two devices in just a couple lines of code. But wait - how did you say Bump works? Over the internet? Right... and what if the user does not have any connection? That's when your app becomes completely useless. So why not use GameKit API instead? I know the name suggests that it has been made for games but what stops you from using it for anything else? Everything is set up for you and you can send data between two devices in a few lines of code as well. Let's take a look how.

First you need to import the GameKit framework to your project. In XCode 4 you need to go to you target Build Phases tab and add GameKit.framework to the Link with Binary Libraries list. Then you need to set up a GKSessionDelegate. You need to carefully decide which of your classes is gonna be the delegate because if you pick the wrong one you end up having to rewrite large parts of your code as I did. The basic question is - when do you need to send and receive data. If it is just a one-off occasion you can set a certain view controller as the delegate but if you need the iPhones to stay connected all the time and the user navigates between multiple views it's probably the best idea to set your ApplicationDelegate as GKSessionDelegate and GKPeerPickerControllerDelegate.

A good tip if your're doing this is to make a macro that allows you to access the ApplicationDelegate from anywhere in your code. Obviously don't forget you have to #import the header file anywhere you need to use this. With this you can access any property of the delegate just by UIAppDelegate.anyProperty and you don't have to write the lengthy piece of code every time.

#define UIAppDelegate ((HelloWorldAppDelegate *)[UIApplication sharedApplication].delegate)

So first thing - the class we will use needs to conform to two protocols as shown below - GKSessionDelegate for handling the session and GKPeerPickerControllerDelegate for estabilishing the connection. Also it is a good idea to set up three properties as show below.

@interface HelloWorldAppDelegate : NSObject <UIApplicationDelegate, GKSessionDelegate, GKPeerPickerControllerDelegate> {
    GKPeerPickerController *connectionPicker;
    GKSession* connectionSession;
    NSMutableArray *connectionPeers;
}
@property (retain) GKSession* connectionSession;
@property (nonatomic, retain) NSMutableArray *connectionPeers;
@property (nonatomic, retain) GKPeerPickerController* connectionPicker;

Then we need to properly initialize all those so add this somewhere to your code (didFinishLaunching or viewDidLoad).

connectionPicker = [[GKPeerPickerController alloc] init];
connectionPicker.delegate = self;
//NOTE - GKPeerPickerConnectionTypeNearby is for Bluetooth connection, you can do the same thing over Wi-Fi with different type of connection
connectionPicker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;
connectionPeers = [[NSMutableArray alloc] init];

Now we need to add methods that are needed to conform to the GKPeerPickerControllerDelegate. There is nothing much to do there, you can just copy them and change the session ID to ID your app will use.

#pragma mark - GKPeerPickerControllerDelegate
- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type
{
    // Create a session with a unique session ID - displayName:nil = Takes the iPhone Name
    GKSession* session = [[GKSession alloc] initWithSessionID:@"com.myapp.connect" displayName:nil sessionMode:GKSessionModePeer];
    return [session autorelease];
}

// Tells us that the peer was connected
- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session
{
    // Get the session and assign it locally
    self.connectionSession = session;
    session.delegate = self;
    
    [picker dismiss];
}

And now comes the most important part - GKSessionDelegate. The principle for sending data is to convert them into NSData. If you are really sure you will need to send just, say, one NSString than you can encode it directly and just send it. But if you need to send anything more complicated I strongly recommend using the technique with an array and NSKeyedArchiver because it leaves plenty of space for later changes and allows you to send different chunks of data. As you will see this is even probably the easiest method for distinguishing what you actually received - you always get encoded array and when you recreate the array you can test whatever elements in it. Note that you could also use NSDictionary if you need to. And don't forget that if you send some custom classes they need to conform to the NSCoding protocol!

//Method for sending data that can be used anywhere in your app
- (void)sendData:(NSArray*)data
{
    NSData* encodedArray = [NSKeyedArchiver archivedDataWithRootObject:data];
    [UIAppDelegate.connectionSession sendDataToAllPeers:encodedArray withDataMode:GKSendDataReliable error:nil];            
    [encodedArray release];            
}

And now the method for receiving data.

#pragma mark - GKSessionDelegate

// Function to receive data when sent from peer
- (void)receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
{
    NSArray *receivedData = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    //Handle the data received in the array
    [receivedData release];
}

- (void)session:(GKSession *)session peer:(NSString *)peerID didChangeState:(GKPeerConnectionState)state {
    if (state == GKPeerStateConnected) {
        // Add the peer to the Array
        [connectionPeers addObject:peerID];
        
        // Used to acknowledge that we will be sending data
        [session setDataReceiveHandler:self withContext:nil];
        
        //In case you need to do something else when a peer connects, do it here
    }
    else if (state == GKPeerStateDisconnected) {
        [self.connectionPeers removeObject:peerID];
        //Any processing when a peer disconnects
    }
}

And finally two methods to call when you want to connect or disconnect usable from anywhere in your app.

- (void)connectToPeers:(id)sender
{
    [UIAppDelegate.connectionPicker show];
}

- (void)disconnect:(id)sender
{
    [UIAppDelegate.connectionSession disconnectFromAllPeers];
    [UIAppDelegate.connectionPeers removeAllObjects];
}

With this tutorial you should be able to set up basic Bluetooth communication between two iOS devices. Obviously there is a lot more in the documentation, take this just as basics that I have learnt somewhere else and slightly refined them.

10 Jun 2011

UIColor from RGB value

This is just a small but incredibly useful snippet - it returns you an instance of UIColor from given RGB value. Invaluable when you're matching your UI elements with your Photoshop graphics or anytime you know need UIColor from RGB.

#define UIColorFromRGB(rgbValue) [UIColor 
                colorWithRed:(((float)((rgbValue & 0xFF0000) >> 16))/255.0) 
                green:(((float)((rgbValue & 0xFF00) >> 8))/255.0) 
                blue:(((float)(rgbValue & 0xFF))/255.0) alpha:1.0]

Put this code just under the #import bit and then use it like this
UIColor *color = UIColorFromRGB(0x800080);

9 Jun 2011

Custom UISlider

Want to create a nice custom UISlider? There is a really simple way. Just use this bit of code in your viewDidLoad method or wherever you initialize the slider.
 UISlider *slider = [[UISlider alloc] init]; 
 UIImage *sliderLeftTrackImage = [[UIImage imageNamed: @"slider_body_min.png"] stretchableImageWithLeftCapWidth: 9 topCapHeight: 0]; 
 UIImage *sliderRightTrackImage = [[UIImage imageNamed: @"slider_body_max.png"] stretchableImageWithLeftCapWidth: 9 topCapHeight: 0]; 
 UIImage *sliderThumb = [[UIImage imageNamed: @"slider_thumb.png"] stretchableImageWithLeftCapWidth: 9 topCapHeight: 0]; 
 [slider setMinimumTrackImage: sliderLeftTrackImage forState: UIControlStateNormal]; 
 [slider setMaximumTrackImage: sliderRightTrackImage forState: UIControlStateNormal]; 
 [slider setThumbImage:sliderThumb forState:UIControlStateNormal]; 
 // Now place you slider in a view and do anything else you want

All you need to do is you need to draw three images - min and max bar for the track and the thumb. And that's it!
6 Jun 2011

UITableView shadows

Following the previous post about UINavigationBar shadow now I show how to do nice UITableView top and bottom shadows. It can be easily done in quite the same fashion - we create two UIViews as our shadows and just use them as header and footer views of our UITableView. Use this bit of code in viewDidLoad method of your UITableView.

 //Footer shadow 
 UIView *footerShadow = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)]; 
 CGColorRef darkColor = [[UIColor blackColor] colorWithAlphaComponent:.5f].CGColor; 
 CGColorRef lightColor = [UIColor clearColor].CGColor; 
 
 CAGradientLayer *bottomShadow = [[[CAGradientLayer alloc] init] autorelease]; 
 bottomShadow.frame = CGRectMake(0,0, self.view.frame.size.width, 10); 
 bottomShadow.colors = [NSArray arrayWithObjects:(id)darkColor, (id)lightColor, nil]; 
 footerShadow.alpha = 0.6; 

 [footerShadow.layer addSublayer:bottomShadow]; 
 self.tableView.tableFooterView = footerShadow; 
 self.tableView.contentInset = UIEdgeInsetsMake(-10, 0, 15, 0); 
 
 //Header shadow 
 UIView *headerShadow = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)]; 
 
 CAGradientLayer *topShadow = [[[CAGradientLayer alloc] init] autorelease]; 
 topShadow.frame = CGRectMake(0, 0, self.view.frame.size.width, 10); 
 topShadow.colors = [NSArray arrayWithObjects:(id)lightColor, (id)darkColor, nil]; 
 headerShadow.alpha = 0.3; 
 
 [headerShadow.layer addSublayer:topShadow]; 
 self.tableView.tableHeaderView = headerShadow; 

This works only for plain style UITableViews, not for the grouped ones. Also, if you are already using header and footer views for something else you can try it this way
//relpace
self.tableView.tableHeaderView = headerShadow;
//with
[self.tableView insertSubview:headerShadow aboveSubview:self.tableView.tableHeaderView];

//and
self.tableView.tableFooterView = footerShadow;
//with
[self.tableView insertSubview:footerShadow belowSubview:self.tableView.tableFooterView];

Dominik Krejcik's Posterous

Czech student in London, 19, sharing iOS development tips, tutorials and stories