简体   繁体   中英

Unable to set custom protocol delegate using ARC with two UITableViewControllers using UINavigationController

I'm trying to set the delegate for my custom protocol that has one required method allowing me to pass an array of objects back in the hierarchy of two UITableViewControllers . My delegate continues to return nil . Due to this, my required method is never called.

I'm wondering if the datasource and delegate implementations with my UITableViewControllers is causing a conflict. Also, perhaps ARC is getting in the way when declaring the delegate?

It should be noted that both UITableViewControllers were built using Storyboard and are navigated using segues within a UINavigationController (not sure if this may be causing issues or not).

The nav is --> AlarmViewController --> AlarmDetailsViewController . I create an Alarm object in my AlarmDetailsViewController that contains all the details for an alarm, place it into an array and I want to pass that array back to my AlarmViewController to be displayed in a custom cell in the table.

NOTE: I want to use the Delegate pattern here. I'm not interested in solutions that invoke NSNotifications or use my AppDelegate class.

AlarmDetailsViewController.h

#import "Alarm.h"

@protocol PassAlarmArray <NSObject>
   @required
   -(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray;
@end

@interface AlarmDetailsViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate> 
{
   //.....   
   id <PassAlarmArray> passAlarmsArrayDelegate;   
}

@property (nonatomic, retain) id <PassAlarmArray> passAlarmsArrayDelegate;

@end

AlarmDetailsViewController.m

#import "AlarmDetailsViewController.h"

@interface AlarmDetailsViewController ()

@end

@implementation AlarmDetailsViewController

@synthesize passAlarmsArrayDelegate;

-(void) viewWillDisappear:(BOOL)animated
{
   NSLog(@"delegate = %@", self.passAlarmsArrayDelegate);  // This prints nil
   [[self passAlarmsArrayDelegate] passAlarmsArray:alarmsArray]; 
}
//....
@end

AlarmViewController.h

@interface AlarmViewController : UITableViewController <UITableViewDataSource, UITableViewDelegate, PassAlarmArray>
{
//...
AlarmDetailsViewController  *alarmDetailsViewController;
}

@property (nonatomic, retain) AlarmDetailsViewController *alarmDetailsViewController;

@end

AlarmViewController.m

#import "AlarmViewController.h"
#import "AlarmDetailsViewController.h"
#import "AlarmTableViewCell.h"
#import "Alarm.h"

@interface AlarmViewController ()

@end

@implementation AlarmViewController

@synthesize alarmDetailsViewController;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // This is where I'm attempting to set the delegate
    alarmDetailsViewController = [[AlarmDetailsViewController alloc]init];
    [alarmDetailsViewController setPassAlarmsArrayDelegate:self];
}

//....

//My @required protocol method which never gets called since my delegate is nil
-(void) passAlarmsArray:(NSMutableArray *)theAlarmsArray 
{
    alarmsTableArray = theAlarmsArray;
    NSLog(@"alarmsTableArray contains:  %@", alarmsTableArray); // Never gets called due to delegate being nil
    NSLog(@"theAlarmsArray contains:  %@", theAlarmsArray); // Never gets called due to delegate being nil
}

@end

I've attempted to set the delegate in a method that fires when a button is pressed in AlarmViewController (as opposed to the viewDidLoad method) but that does not work either.

I'm assuming I've got a logic flow error somewhere here . . . but nearly 2 days of hunting and rebuilds haven't uncovered it. Ugh.

You're setting your delegate in the wrong place, and on a different instance of the controller than the one you will get when you do the segue. You should set the delegate in the prepareForSegue method if you're pushing AlarmDetailsViewController from AlarmViewController

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    AlarmDetailsViewController *alarm = segue.destinationViewController;
    alarm.passAlarmsArrayDelegate = self;
}

You really need to understand the life cycle of view controllers, how and when they're instantiated, and when they go away. This is the very heart of iOS programming, and Apple has extensive documentation on it. Reading up on segues would also be very useful. A segue (other then an unwind segue) always instantiates a new instance of the destination controller. So, when your segue is performed, whether directly from a button, or in code, a new (different from the one you alloc init'd directly) details controller is instantiated. Before that segue is performed, prepareForSegue: is called, and that's when you have access to the one about to be created. That's the place to set a delegate or pass any information on to the destination view controller.

自使用ARC以来,您是否尝试用(非原子,强)替换(非原子,保留)?

Auto-synthesized properties like your alarmDetailsViewController property have backing ivars prefixed with underscores, eg _alarmDetailsViewController. Your alarmDetailsViewController ivar (the alarmDetailsViewController declared inside the @interface ... {} block in AlarmViewController.h) is different from the backing ivar of your alarmDetailsViewController property.

Just delete your alarmDetailsViewController ivar and use the @property, preferably through self.alarmDetailsViewController.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM