通过多个层次结构传递代理

时间:2013-03-22 22:38:43

标签: iphone objective-c

我写了一个自定义类TagsScrollView,它在滚动视图中显示标签。

当按下标签时,TagsScrollView依赖其代理来实现该做什么。几乎所有时间,这都涉及:

  1. 将标签索引更改为其他索引
  2. 将TagsDetailVC推送到当前导航控制器。
  3. 现在,这就是我的应用程序的结构:

    enter image description here

    虚线表示“有”关系。 MainVC有一个FeedView,它有一些FeedCellViews,而每个FeedCellViews都有一个TagsScrollView。

    实线表示“推”关系。 ImageDetailVc被推送到MainVC的navController。

    如何组织我的代码,以便可以优雅地将TagsScrollView的委托指向MainVC?

    现在我已经定义了以下内容:

    TagsScrollView.h

    @protocol TagPressedDelegate<NSObject>
    @required
    - (void)tagPressed:(id)sender forQuery:(NSString *)query;
    @end
    

    FeedCellView.m

    self.tagsScrollView.tagPressedDelegate = self.tagPressedDelegate

    FeedView.m

    self.cells[0].tagPressedDelegate = self.tagPressedDelegate

    MainViewVC.m

    self.feed.tagPressedDelegate = self
    ....
    
    - (void)tagPressed... 
    

    我该如何避免这种模式?我能做得更好吗?我应该让TagsScrollViewDelegate扩展ScrollViewDelegate吗?

1 个答案:

答案 0 :(得分:0)

你绝对可以做得更好,删除委托模式,使用块。

将基于块的属性添加到TagsScrollView .h文件

@property (copy, nonatomic) void (^tagPressedBlock)(id sender, NSString *query);

<。>在.m文件中添加相关的回调

- (void)tagPressed:(id)sender {
  if (_tagPressedBlock) {
    _tagPressedBlock(sender, self.query); // I'm assuming that the query is your iVar
  }
}

像这样分配属性

tagsScrollView.tagPressedBlock = ^(id sender, NSString *query) {
  // do stuff with those parameters
}

那就是“做得更好”

至于如何将标记按下的事件传递给MainVC类,您应该使用NSNotificationCenter。

在全局可见的地方定义通知名称,例如我建议在Prefix.pch文件中创建一个Defines.h文件和#including它。

无论如何,定义通知名称:

static NSString *const TagPressedNotification = @"TagPressedNotification";

接下来在执行-tagPressed:时发布该通知,并将有价值的信息封装到userInfo字典中:

- (void)tagPressed:(id)sender {
  [[NSNotificationCenter defaultCenter] postNotificationName:TagPressedNotification object:nil userInfo:@{@"sender" : sender, @"query" : self.query, @"scrollView" : self.tagScrollView}];
  //.. code 
}

接下来,将MainVC作为观察者添加到该通知中:

MainVC.m

- (void)viewDidLoad {
  [super viewDidLoad];
  [[NSNotificationCenter defaultCenter] addObserver:self
                                           selector:@selector(tagPressed:)
                                               name:TagPressedNotification
                                             object:nil];
}

在MainVC中实施-tagPressed:方法

- (void)tagPressed:(NSNotification *)notification {
  id sender = notification.userInfo[@"sender"];
  NSString *query = notification.userInfo[@"query"];
  TagScrollView *scrollView = notification.userInfo[@"scrollView"];
  if (scrollView == myScrollView) { // the one on your mainVC
    // do stuff
  }
}

添加时不要忘记将自己清理出NotificationCenter的注册表:

- (void)dealloc {
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

修改

我想你也应该传递滚动视图,它是发送者,因为你的mainVC也包含滚动视图。编辑了代码

另一个编辑

在Defines.h文件中创建枚举定义

enum {
  TagSenderTypeFeed = 1,
  TagSenderTypeImageDetail
};
typedef NSInteger TagSenderType;

创建通知时,在通知的userInfo字典@"senderType" : @(TagSenderTypeFeed)

中添加适当的枚举值