Showing posts with label ios. Show all posts
Showing posts with label ios. Show all posts

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