Saturday, September 14, 2013

Unique Auto Increment Values for NSManagedObjects (Core Data)

Auto Increment Values for NSManagedObjects

Unique Auto Increment Values for NSManagedObjects

Core Data automatically generate auto increment id for each managed object.

The unique auto id is however not exposed through the api. However, there is [NSManagedObject objectID] method that returns the unique path for each object.

Its usually in the form <x-coredata://SOME_ID/Entity/ObjectID> e.g <x-coredata://197823AB-8917-408A-AD72-3BE89F0981F0/Message/p12> for object of Message entity with ID `p12. The numeric part of the ID (last seqment of the path) is the auto increment value for each object.

Here is a method that returns the auto increment integer value for an NSManagedObject

@implementation NSManagedObject(Extra)

-(NSUInteger)autoId{

NSURL *url = [[self objectID] URIRepresentation];
//get full url
NSString *url_string = [url absoluteString];

//split with a /
NSArray *parts = [url_string componentsSeparatedByString:@"/"];

NSString *last_segment=[parts objectAtIndex:[parts count]-1];

//p#
NSString *number_part = [last_segment stringByReplacingOccurrencesOfString:@"p" withString:@""];

NSUInteger auto_id = [number_part integerValue];

number_part =nil;
last_segment=nil;
parts=nil;
url=nil;
url_string=nil;


return auto_id;

}
@end

Side Note

Do not use this method on the fly. When I first used this method in our chat app, it took much time to render the messages. I was using the auto increment value to order the messages.

To solve this, I added a new attribute to the Messages entity called auto_increment_integer. Anytime I create and save a new object, I set its auto_increment_integer value to the return value of autoId.

Like this:

    NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];

    Message *m = [Message MR_createInContext:localContext];
    //Set attributes here
    //....
    //save object
    [localContext MR_saveToPersistentStoreAndWait];

    //set the auto increment value
    m.auto_increment_id=[NSNumber numberWithInt:[m autoId]];
    //save again
    [localContext MR_saveToPersistentStoreAndWait];

Hope this helps.

Saturday, August 31, 2013

Custom Back Button UINavigationBar

Custom Back Button - UINavigationBar

Custom Back Button - UINavigationBar

IOS comes with useful controls for developers which makes app development and UI navigation pretty easy.

One of such controls is the UINavigationController.

UINavigationController allows you to push ViewControllers onto a stack. It comes with a UINavigationBar which automatically contains back button to go to the previous View from the current view.

Using UINavigationController is common is most ios apps.

The back button which is a UIBarButtonItem usually comes with the defaut chrome for the IOS app.

However, if you have a different design for your app, you may as well want to have a custom back button.

There are two ways to do this:

1) Change the background Image of the back button

2) Create a custom UIBarButtonItem as the back button (and hide the original back button)

This post will focus on the second method. The first method works in situations where you dont want to change the text on the back button, just the background image or the theme.

UINavigationBar

The UINavigationBar is the top bar that's is automatically placed at the top of UINavigationController to allow for navigating back and forth.

The UINavigationBar of a UINavigationController can be accessed (from a UIViewController)

self.navigationItem

So to get our custom back button we are basically doing this;

  1. Hide the default back button
  2. Create a custom UIBarButtonItem
  3. Add it to the UINavigationBar

Another thing we need to do is to ensure we do steps 2 and 3 only when we have are on a view other than the first on the stack.

  1. Create a new single view application from Xcode
  2. Add UIViewController call it BaseUIViewContoller

In BaseUIViewController.m, make the following changes to the default viewDidLoad method

    -(void)viewDidLoad
    {
        [super viewDidLoad];
        //hide the default back button 
        [self.navigationItem setHidesBackButton:YES];
    }
  1. We are going to add a method that will create a custom UIBarButtonItem using our custom back button image

In BaseUIViewContoller.h add this

    -(UIBarButtonItem*)barButtonWithImage:(UIImage*)image 
    target:(id)target 
    action:(SEL)action;

In BaseUIViewController.m add this for the implementation of the method

    -(UIBarButtonItem*)barButtonWithImage:(UIImage*)image 
    target:(id)target 
    action:(SEL)action
    {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];

    [button setBackgroundImage: [image stretchableImageWithLeftCapWidth:7.0 topCapHeight:0.0] forState:UIControlStateNormal];

    [button setBackgroundImage:image forState:UIControlStateHighlighted];

    button.frame = CGRectMake(0.0, 0.0, image.size.width, image.size.height);

    [button addTarget:self action:action  forControlEvents:UIControlEventTouchUpInside];

    UIView *v=[[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, image.size.width, image.size.height) ];

    [v addSubview:button];

    UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithCustomView:v];

    return barButton;
    }

Finally lets add another method that will show the back button only when we are not on the first ViewController in a NavigationViewController

Remember we are hidding the back button. However, the navigationItem property of the UIViewController has leftButtonItems which is array of buttons that will appear left side of the UINavigationBar. So we ca add our custom UIBarButtonItem to this array and have it act as our back button!

In BaseUIViewController.h add this

-(void)setupBackButton;
-(void)goBack;

In BaseUIViewController.m add this for the implementation of the method

-(void)setupBackButton{
    if(self.navigationController && 
        [self.navigationController.childViewControllers count]>1){
        UIBarButtonItem *back = 
        [self barButtonWithImage:[UIImage imageNamed:@"Back"]
         target:self action:@selector(goBack)];
        self.navigationItem.leftBarButtonItems = 
        [NSArray arrayWithObjects:back, nil];
}
-(void)goBack{
    [self.navigationController popViewControllerAnimated:YES];
}

Now we will make all our UIViewControllers inherit from our BaseUIViewController.

In any of our UIViewControllers viewDidLoad method we can call the setupBackButton and that will put our back button in the nav bar.

-(void)viewDidLoad{
    [super viewDidLoad];
    [self setupBackButton];
    //do other stuff...
}

This will setup the back button and allows you to navigate back in the UINavigationController views.

Hope this helps.

Thanks for reading

Tuesday, January 15, 2013

Setting up Laravel-4 on Webfaction

Setting up laravel 4 on [**Webfaction**](http://webfaction.com?affiliate=jeff01)

Setting up laravel 4 on Webfaction

  1. Create your domain or subdomain. E.g laraveltest.hostname.com

    Check here on how to create add domains or subdomains on webfaction.

  2. Create your application. Make sure you select Static/CGI/PHP and PHP 5.4 runtime

    Check here on how to create add applications on webfaction

  3. Create your website and add domain and application you've created. E.g laraveltest

    Check webfaction on how to create website on webfaction

Test in browser

http://laraveltest.hostname.com

and see you have Hello World displayed.

Setting up laravel 4

Installing composer

To install composer to your home directory

$cd ~

Run this using php54 runtime

$php54 -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"

This will install composer to your home directory so you can run it like composer.phar

Installing latest laravel-4 version

As of this writing laravel 4 is still in better. To get the lastes go to http://four.laravel.com and get the latest version.

I got my version from https://github.com/laravel/laravel/archive/develop.zip

$ cd ~

$ wget https://github.com/laravel/laravel/archive/develop.zip

$ unzip develop

This will unzip the content of develop to laravel-develop directory in the home directory

Ready to install laravel dependencies

$ cd ~

$ cd laravel-develop

$ php54 ~/composer.phar install

This will install all laravel dependencies into the vendor directory in the laravel-develop directory

Create a directory in your home folder that will take all laravel apps

$ cd ~

$ mkdir laravelapps

$ cd laravelapps

$ mkdir laraveltest

Now copy the content of ~/laravel-develop/public directory into ~/webapps/laraveltest.

You should have these files inside the directory ~/webapps/laraveltest

index.php
.htaccess
favicon.ico

Now copy all files and folders inside ~/laravel-develop except vendor and public to ~/laravelapps/laraveltest/


We are almost there!


Editing index.php to point to the the right files

$ cd ~/webapps/laraveltest

$ nano index.php

Change this line

require __DIR__.'/../vendor/autoload.php';

To point to the new path:

require '/home/<<your-webfactio-username>>/laravel-develop/vendor/autoload.php';

Or

require '~/laravel-develop/vendor/autoload.php';

Then change this line

require_once __DIR__.'/../start.php';

To

require_once '/home/<<your-webfactio-username>>/laravelapps/laraveltest/start.php';

Update:

In order to use artisan commands do the same changes you made above to index.php in this file: ~/laravelapps/laraveltest/artisan


Done!!

Now check

http://laraveltest.hostname.com

You should see Hello World from laravel default '/' route.

Happy coding!!

Cheers!! @badu_bizzle

Special thanks to Taylor Otwell for creating the awesome PHP framework