Krish
Krish

Reputation: 4232

Protocols is not working

Hi I am adding one custom button programmatically on navigation bar and i have written all button properties in my background class and i am calling this method from my main class

And here I have used protocols for getting button touching event in my main class from background class but it's not working using protocols

my code:-

background class:-

BackGroundClass.h

#import <UIKit/UIKit.h>

@protocol buttonprotocol<NSObject>
@required
- (void) buttonTapped;
@end

@interface BackGroundClass : UIViewController

@property (nonatomic, weak) id<buttonprotocol> delegate;

@end

BackGroundClass.m

#import "BackGroundClass.h"

@interface BackGroundClass ()

@end

@implementation BackGroundClass
@synthesize delegate;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)backbutton: (UINavigationItem *)navigationitem
{
        UIImage* image3 = [UIImage imageNamed:@"back.png"];
        CGRect frameimg = CGRectMake(15,5,25,25);

        UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
        [someButton setBackgroundImage:image3 forState:UIControlStateNormal];
        [someButton addTarget:self action:@selector(Back_btn:)
             forControlEvents:UIControlEventTouchUpInside];
        [someButton setShowsTouchWhenHighlighted:YES];

        UIBarButtonItem *mailbutton =[[UIBarButtonItem alloc] initWithCustomView:someButton];
        navigationitem.leftBarButtonItem = mailbutton;
}

- (void)Back_btn :(id)sender
{
   [delegate buttonTapped];
}

@end

main class:-

mainclass.h

#import <UIKit/UIKit.h>
#import "BackGroundClass.h"

@interface mainclass : UIViewController<buttonprotocol>

mainclass.m

#import "mainclass.h"
#import "BackGroundClass.h"

@interface mainclass ()
{
 BackGroundClass * bg;
}

@end

@implementation mainclass

- (void)viewDidLoad {
    [super viewDidLoad];

    bg = [[BackGroundClass alloc]init];
    [bg backbutton:self.navigationItem];
}

- (void)buttonTapped
{
    NSLog(@"ok it's 2");
}

but that above button tapped a method isn't called what I did wrong?

Upvotes: 0

Views: 50

Answers (2)

Alex Posplaw
Alex Posplaw

Reputation: 116

First of all, using Class in class names is bad practice. As for View Controllers you should use either ViewController or VC postfix for your class names.

For example, the proper names of your Objective-C classes would be: BackgroundViewController, MainViewController

Secondly, ViewController instances are used to react to user interaction with the view attached to this ViewController and provide visible changes based on Data component of MVC work. So, there is no reason to use second, in your case BackgroundViewController (BackgroundClass).

For more info about MVC pattern, please refer this link: Apple's MVC articles

As there is no need in external ViewController we also should remove the delegate using and place all logic inside this main View Controller.

Thirdly, as mentioned in Apple's Mobile HIG, buttons should have a height around 44px, so your back button's size of 25x25 would make most users experience hard trying to tap on it.

At last, you should receive the class with code similar to it:

MainViewController.h

#import <UIKit/UIKit.h>

@interface MainViewController : UIViewController


@end

MainViewController.m

#import "MainViewController.h"

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIImage *icon = [UIImage imageNamed:@"back.png"];

    static CGFloat defaultButtonSize = 44.; // Default button's tap area size

    CGSize buttonSize = CGSizeMake(defaultButtonSize, defaultButtonSize);
    // The size image should take inside the button
    CGSize imageSizeInsideButton = CGSizeMake(25., 25.); 

    CGRect frameimg = CGRectMake(15., 5., defaultButtonSize, defaultButtonSize);

    UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
    [someButton setImage:icon forState:UIControlStateNormal];
    [someButton addTarget:self
                   // No need to put colon after method name,
                   // since you have no use of control that triggered action
                   action:@selector(backButtonClicked)                                      
         forControlEvents:UIControlEventTouchUpInside];

    someButton.showsTouchWhenHighlighted = YES;

    // Calculate edge insets so image will take the size 
    // you specified dozen of lines before
    CGFloat imageVerticalPaddingInButton = (buttonSize.height - imageSizeInsideButton.height) / 2.;
    CGFloat imageHorizontalPaddingInButton = (buttonSize.height - imageSizeInsideButton.height) / 2.;

    // Apply it to button
    someButton.imageEdgeInsets = UIEdgeInsetsMake(imageVerticalPaddingInButton,
             imageHorizontalPaddingInButton, 
             imageVerticalPaddingInButton, 
             imageHorizontalPaddingInButton);

    UIBarButtonItem *mailbutton =[[UIBarButtonItem alloc] initWithCustomView:someButton];
    self.navigationItem.leftBarButtonItem = mailbutton;
}

// As stated in "addTarget", there is no "sender" since you don't really need it
// If you ever would need the use of it, 
// don't forget to put colon in "addTarget" UIButton's method
// and place something like :(UIButton *)buttonThatClicked
// after methodName
- (void)backButtonClicked {
    // Get back to your previous view controller or do whatever you like there
    [self.navigationController popViewControllerAnimated:YES];
}

@end

But if you want to use this thing in as many View Controllers as possible, then you should create the category:

UIViewController+CustomBackButton.h

#import <UIKit/UIKit.h>

@interface UIViewController (CustomBackButton)

- (void)setBackButtonImage:(UIImage *)image withSize:(CGSize)size target:(id)target selector:(SEL)selector;

@end

UIViewController+CustomBackButton.m

#import "UIViewController+CustomBackButton.h"

@implementation UIViewController (CustomBackButton)

- (void)setBackButtonImage:(UIImage *)image withSize:(CGSize)size target:(id)target selector:(SEL)selector {
    static CGFloat defaultButtonSize = 44.;

    CGSize buttonSize = CGSizeMake(defaultButtonSize, defaultButtonSize);

    CGRect frameimg = CGRectMake(15., 5., defaultButtonSize, defaultButtonSize);

    UIButton *someButton = [[UIButton alloc] initWithFrame:frameimg];
    [someButton setImage:image forState:UIControlStateNormal];
    [someButton addTarget:target
                   action:selector
         forControlEvents:UIControlEventTouchUpInside];

    someButton.showsTouchWhenHighlighted = YES;

    CGFloat imageVerticalPaddingInButton = (buttonSize.height - size.height) / 2.;
    CGFloat imageHorizontalPaddingInButton = (buttonSize.height - size.height) / 2.;

    someButton.imageEdgeInsets = UIEdgeInsetsMake(imageVerticalPaddingInButton,
                                                  imageHorizontalPaddingInButton,
                                                  imageVerticalPaddingInButton,
                                                  imageHorizontalPaddingInButton);

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithCustomView:someButton];
    self.navigationItem.leftBarButtonItem = backButton;
}

@end

And then your View Controller's implementation file will be much cleaner.

MainViewController.m

#import "MainViewController.h"
#import "UIViewController+CustomBackButton.h"

@implementation MainViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIImage *icon = [UIImage imageNamed:@"back.png"];
    CGSize iconSize = CGSizeMake(25., 25.);

    [self setBackButtonImage:icon
                    withSize:iconSize
                      target:self
                    selector:@selector(backButtonClicked)];
}

- (void)backButtonClicked {
    // Get back to your previous view controller or do whatever you like there
    [self.navigationController popViewControllerAnimated:YES];
}

@end

And then you can use this on every ViewController to customize your back button.

Upvotes: 1

Rajat
Rajat

Reputation: 11127

When you are creating the object of your BackGroundClass class, then you are not setting the delegate of the class to self, thats why your delegate method is not calling, try it like this

bg = [[BackGroundClass alloc]init];
bg.delegate = self;

Upvotes: 1

Related Questions