user4615157
user4615157

Reputation:

single uiview for many viewcontrollers

I have a viewcontroller name it as viewcontroller1. I have dragged a uiview to this viewcontroller and added some buttons to that view with actions. And also a custom view class is created for that uiview. This uiview is acting as a top bar for viewcontroller1. I have some more viewcontrollers and I am using the same uiview for those viewcontrollers too by getting the uiview using viewwithtag method. But the delegates are not working when I am using this method. I am getting a thread1 exc_bad access when the delegates are called from the uiview class. Any help is appreciated. This is my uiview class

//topview.h

@protocol buttonprotocol <NSObject>

-(void) button1pressed;
-(void) button2pressed;

@end
#import <UIKit/UIKit.h>

@interface topview : UIView
- (IBAction)button1action:(id)sender;
- (IBAction)button2action:(id)sender;
@property (nonatomic,assign) id <buttonprotocol> delegate;
@property (weak, nonatomic) IBOutlet UIButton *button1;
@property (weak, nonatomic) IBOutlet UIButton *button2;
@end

//topview.m

#import "topview.h"

@implementation topview

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    // Drawing code
}
*/
- (IBAction)button1action:(id)sender
{
    [self.delegate button1pressed];
}
- (IBAction)button2action:(id)sender
{
    [self.delegate button2pressed];
}
@end

The given below is the first viewcontroller

// ViewController.h

#import <UIKit/UIKit.h>
#import "topview.h"
#import "button1ViewController.h"
#import "button2ViewController.h"
@interface ViewController : UIViewController
<buttonprotocol>
@property (weak, nonatomic) IBOutlet topview *topviewobj;


@end

// ViewController.m

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    _topviewobj.delegate=self;
    UIView *newview=[[UIView alloc]initWithFrame:CGRectMake(0, 250, 320, 100)];
    newview=[self.view viewWithTag:1];
    [self.view addSubview:newview];
    // Do any additional setup after loading the view, typically from a nib.
}
-(void) button1pressed
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button1ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button2ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end

the given below is the view controller class for the viewcontroller when the first button is tapped.

// button1ViewController.h

#import <UIKit/UIKit.h>
#import "topview.h"
#import "ViewController.h"
#import "button2ViewController.h"
@class topview;
@interface button1ViewController : UIViewController
<buttonprotocol>
{
    UIView *newview;
    topview *topviewobj;
}
@end

// button1ViewController.m

#import "button1ViewController.h"

@interface button1ViewController ()

@end

@implementation button1ViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    topviewobj=[topview new];
    topviewobj.delegate=self;
    NSLog(@"%@",topviewobj.delegate);
    self.view.backgroundColor=[UIColor purpleColor];
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    newview=[[UIView alloc]init];
    newview=[vc.view viewWithTag:1];
    UIButton *backbutton=[[UIButton alloc]init];
    [backbutton setTitle:@"Back" forState:UIControlStateNormal];
    [backbutton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [backbutton setFrame:CGRectMake(5, 30, 60, 30)];
    [backbutton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
    [newview addSubview:backbutton];
    [self.view addSubview:newview];
    // Do any additional setup after loading the view.
}
-(void) back
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
-(void) button1pressed
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button1ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button2ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

Given below is the class for viewcontroller for the viewcontroller when second button is tapped.

// button2ViewController.h

#import <UIKit/UIKit.h>
#import "topview.h"
#import "ViewController.h"
@class topview;
@interface button2ViewController : UIViewController
<buttonprotocol>
{
    UIView *newview;
    topview *topviewobj;
}
@end

// button2ViewController.m

#import "button2ViewController.h"

@interface button2ViewController ()

@end

@implementation button2ViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    topviewobj=[topview new];
    topviewobj.delegate=self;
    NSLog(@"%@",topviewobj.delegate);
    self.view.backgroundColor=[UIColor purpleColor];
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    newview=[[UIView alloc]init];
    newview=[vc.view viewWithTag:1];
    UIButton *backbutton=[[UIButton alloc]init];
    [backbutton setTitle:@"Back" forState:UIControlStateNormal];
    [backbutton setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [backbutton setFrame:CGRectMake(5, 30, 60, 30)];
    [backbutton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];
    [newview addSubview:backbutton];
    [self.view addSubview:newview];
    // Do any additional setup after loading the view.
}
-(void) back
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
-(void) button1pressed
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button1ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}
-(void) button2pressed
{
//    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
//    button2ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button2ViewController"];
//    [self presentViewController:vc animated:NO completion:nil];
}


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

This is all I got. I can't show my original code due to privacy concerns. This is a sample created to show the issue. I can't upload images as I have low reputation.

Upvotes: 2

Views: 72

Answers (1)

Skyler Lauren
Skyler Lauren

Reputation: 3812

This looks highly suspect...

UIView *newview=[[UIView alloc]initWithFrame:CGRectMake(0, 250, 320, 100)];
newview=[self.view viewWithTag:1];
[self.view addSubview:newview];

You shouldn't have to alloc init a new view if the next line you are going to use viewWithTag because that view would already be inited. Also in the next line you call addSubView on the same thing you just got the view which would only work if the view was already added.

Edit

After further inspection of your code I see what you are trying to do. There are a couple of things to note. If you want to pass an object to a new view controller you can do that when you create the new view controller.

UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
button1ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"button1ViewController"];

//if button1ViewController had a property for topviewobj instead of an instance variable.
button1ViewController.topviewobj = (topview *)[self.view viewWithTag:1];
[self presentViewController:vc animated:NO completion:nil];

//in button1ViewController viewDidLoad
self.topviewobj.delegate = self;
[self.view addSubView:self.topviewobj];

With that being said I think what you really want to do is look into nibs or create topview just in code.

If just in code it would be something like

_topviewobj = [[topview alloc]initWithFrame:CGRectMake(0,250, 320, 100)];
_topviewobj.delegate = self;
[self.view addSubview:_topviewobj];

Also this will likely cause issues in the future...

-(void) back
{
    UIStoryboard *storyboard=[UIStoryboard storyboardWithName:@"Main" bundle:nil];
    ViewController *vc=[storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
    [self presentViewController:vc animated:NO completion:nil];
}

Creating new UIViewControllers over and over again isn't ideal. Try this...

-(void) back
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

As I said before I would look into nibs or just creating a UIView Subclass and alloc/init, set delegate, and add as subview when you need one.

I hope all that makes sense and helps.

Upvotes: 1

Related Questions