使用委托在 UIPopoverViewController 和 MainViewController 之间进行通信

Posted

技术标签:

【中文标题】使用委托在 UIPopoverViewController 和 MainViewController 之间进行通信【英文标题】:Using a delegate to communicate between a UIPopoverViewController and a MainViewController 【发布时间】:2012-05-02 21:16:03 【问题描述】:

我正在开发一个 iPad 应用程序,该应用程序具有一个主视图(在本例中为 MKMapView)和一个包含 UITableViewController 的 PopoverView 控制器。 UITableview 中的内容包含许多变量元素,我需要这些元素在 MapView 上放置注释引脚。这些变量会根据选择的行而变化。我的想法是使用委托来完成此任务,但我正在努力实现它。

我已经在 showIncidentList 方法中声明了委托(参见随附的代码)。我的问题是,这个自定义委托是否适合这个期望的结果,如果是这样,我缺少什么可以让我在委托中传达信息并使用来自委托的更新信息调用主视图上的 plotCallLocations 方法。

相关代码:

SearchViewController.h //popoverViewController 类

@protocol IncidentPickerDelegate <NSObject>

- (void)incidentSelected:(NSMutableArray *)incidentDetail;

@end

@interface SearchViewController : UITableViewController  <UITableViewDelegate, UITableViewDataSource>  
__weak id<IncidentPickerDelegate> _delegate;


@property (nonatomic, retain) NSMutableArray *incidentDetails;
@property (nonatomic, weak) id<IncidentPickerDelegate> delegate;
@end

SearchViewController.m

#import "TwitterSearchViewController.h"
#import "CallViewController.h"

@implementation SearchViewController

@synthesize delegate = _delegate;
@synthesize incidentDetails= _incidentDetails;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 

_incidentDetails = [[NSMutableArray alloc] initWithObjects:[textItems objectAtIndex:0], [textItems objectAtIndex:1], lat, lon, nil];     //textItems is an NSArray of parsed JSON data, lat and lon are int's

 NSLog(@"_delegate = %@", _delegate);
        if ([_delegate respondsToSelector:@selector(incidentSelected:)]) 
            NSMutableArray *incidentDet = _incidentDetails;
            [_delegate incidentSelected:incidentDet];
 NSLog(@"incidentDetail ----> %@", incidentDet);
 

@end

CallViewController.h //MainViewController

#import "SearchViewController.h"

@interface CallViewController : UIViewController <CLLocationManagerDelegate, MKMapViewDelegate, UIAlertViewDelegate, IncidentPickerDelegate> 


@property (nonatomic, retain) UIPopoverController *incidnetListPopover;
@property (nonatomic, retain) SearchViewController *incidentPicker;

-(IBAction)showIncidentList:(id)sender;

CallViewController.m

#import "CallViewController.h"
#import "SearchViewController.h"

@implementation CallViewController

@synthesize incidnetListPopover = _incidnetListPopover;
@synthesize incidentPicker = _incidentPicker;

UIStoryboard*  sb = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                              bundle:nil];

if (_incidentPicker == nil) 
    self.incidentPicker = [sb instantiateViewControllerWithIdentifier:@"SearchViewController"];
    _incidentPicker.delegate = self;

    self.incidnetListPopover = [[UIPopoverController alloc] 
                                initWithContentViewController:_incidentPicker];               


[self.incidnetListPopover presentPopoverFromBarButtonItem:sender 
                                permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];




- (void)incidentSelected:(NSMutableArray *)incidentDetail 


//    for (id<MKAnnotation> annotation in _mapView.annotations) 
//      [_mapView removeAnnotation:annotation];

NSLog(@"plotCall called");
NSNumber * latitude = [incidentDetail objectAtIndex:2];
NSNumber * longitude = [incidentDetail objectAtIndex:3];
NSString * name = [incidentDetail objectAtIndex:1];
NSString * address = [incidentDetail objectAtIndex:0];
CLLocationCoordinate2D coordinate;
coordinate.latitude = latitude.doubleValue;
coordinate.longitude = longitude.doubleValue;  

CallLocation *annotation = [[CallLocation alloc] initWithName:name address:address coordinate:coordinate];
[_mapView addAnnotation:annotation];  

[self.incidnetListPopover dismissPopoverAnimated:YES];


【问题讨论】:

【参考方案1】:

自定义委托方法适用于这种情况。

主要问题是CallViewController 没有实现IncidentPickerDelegate 协议中指定的确切方法incidentSelected:(顺便说一句,我假设“TwitterSearchViewController”是一个错字,应该是“SearchViewController”,反之亦然。)

尽管CallViewController 有方法plotCallLocations: 也接受一个数组,但它并没有被命名为准确 incidentSelected:(它必须是)。

您应该会收到一些关于此的编译器警告。

因此,当SearchViewController 调用该协议方法时,它可能会因“无法识别的选择器”错误而崩溃。

这里有一些解决方案(第一个是最简单的):

CallViewController 中,将plotCallLocations: 更改为incidentSelected: 在协议中,将incidentSelected:改为plotCallLocations:CallViewController 中,添加incidentSelected: 方法,然后从那里调用plotCallLocations:

另外(不会引起问题,但是),在SearchViewController 中,与其检查委托是否为nil,不如检查委托是否确实具有您将要使用respondsToSelector: 调用的方法。

为此,首先您必须使IncidentPickerDelegate 实现NSObject 协议:

@protocol IncidentPickerDelegate<NSObject>

现在在SearchViewController,而不是检查代理是否为nil

if ([_delegate respondsToSelector:@selector(incidentSelected:)])

【讨论】:

奇怪的是,当方法名称和委托名称不同时,我没有收到任何编译器警告或错误。我已经更新了我的代码和以上内容以反映您建议的更改。到目前为止,让 eventSelected 方法运行还没有运气。请注意,我有一个 NSLog 来测试代码是否被访问过,而它没有被访问过。感谢您的帮助! 在 didSelectRowAtIndexPath 中放置断点或 NSLog 并确保代码按预期运行。检查它是否通过了“respondsToSelector”条件。 它似乎。我记录了刚刚通过 respondsToSelector 条件的输出,并且 NSMutableArray 内容记录在控制台中。 你的意思是它没有通过那个条件吗?在 respondsToSelector 检查之前,输入 NSLog(@"_delegate = %@", _delegate); add 看看它说了什么。 我看不出它应该为空的任何理由。在presentPopoverFromBarButtonItem之前,放NSLog(@"_incidentPicker.delegate = %@", _incidentPicker.delegate);

以上是关于使用委托在 UIPopoverViewController 和 MainViewController 之间进行通信的主要内容,如果未能解决你的问题,请参考以下文章

C# 委托的简单使用

QT QTableView 使用委托

委托+内置委托方法

限价委托和市价委托有啥 区别?如何 使用?

委托和事件

为啥使用弱指针进行委托?