ios - 协议(protocol)类别和传递信息

标签 ios objective-c protocols

我有一个创建ObjectA的视图控制器。然后,对象A创建对象B。 ObjectB需要从视图控制器获取一些值(我需要在创建对象后可以更改的值)。

我正在尝试找出检索值的最佳方法。我首先想到的是协议。到目前为止,我仅在对象内创建了协议:

#import <UIKit/UIKit.h>

@protocol AnalysisTypeTableDelegate;

@interface AnalysisTypeTableViewController : UITableViewController

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

@property (strong, nonatomic) NSArray *dataSource;

@property (nonatomic) BOOL allowRefresh;

@end

@protocol AnalysisTypeTableDelegate <NSObject>

-(void)returnAnalysisType:(NSString *)type;

@end


如何创建协议类(例如创建新文件,objective-c协议)?

那如何将它们链接在一起? ObjectA有一个协议,我是否可以执行以下操作:

// View controller and objectB both conform to myProtocol

// view controller creates objectA
myObjectA.delegate = self

// when objectA creates objectB
myObjectB.delegate = self.delegate


还是有更好的方法来检索我需要的值?

编辑:

我想我需要做这样的事情:

objectA的协议:

@protocol objectADelegate

-(NSDictionary)requestViewController;

@end


objectB的协议:

@protocol objectBDelegate

-(NSDictionary *)requestObjectA;

-(void)updateList:(NSSarray *)list;

@end


在myObjectB中

-(NSDictionary *)requestObjectA {
    NSDictionary *extents = [self.delegate requestObjectA];
}

-(void)serverCall {
    // make server call, get list
    ...
    // update myObjectA with new list
    [self.delegate updateList:newList];


在myObjectA中

-(NSDictionary *)requestObjectA {
    return [self.delegate requestViewController];
}

-(void)updateList:(NSArray)list {
    // updates list
}


在视图控制器

-(NSDictionary *)requestViewController;
    return self.mapkit.exents;
}

最佳答案

我假设您是说这是从您的视图控制器调用的:

myObjectA.delegate = self


并且您正在从对象A调用以下行:

myObjectB.delegate = self.delegate


从技术上讲,您可以做到这一点,尽管我发现该构造有些混乱。甚至有一点问题,因为您没有提供任何机制让视图控制器说“好,我不想再成为delegate”,因为它大概只知道myObjectA。您没有任何机制让视图控制器告诉myObjectB它不再是其delegate,因为假定视图控制器甚至都不知道B的存在。



使用模型-视图-控制器模式

delegate的概念是“我想告诉我delegate一些东西,或提出一些要求”之一。另一方面,如果您的目标是共享数据,则我倾向于从委托协议模式转移到model-view-controller(MVC)模式,我们将重点关注“模型”部分:


创建一个Model类来保存模型数据;
让视图控制器实例化一个Model类对象;
将指向Model对象的指针从一个视图控制器或对象传递到下一个(或通过其他方式使该模型对象可通过其他类(例如,单例模式,应用程序委托属性等)访问);
确保您的Model类具有与要维护的数据相关的属性(这样,其他类可以使用Model为您合成的访问器方法)。


从概念上讲,这与您使用delegate指针概述的内容非常相似,但不包含delegate的含义,即您不仅要访问数据,而且可以告诉控制器执行该操作。的东西。在委托人协议模式中,委托人通常应能够随时选择退出成为delegate的能力。



处理模型数据变化的不同方法

有几种方法可以将更改反映到其他对象中的模型对象(例如,告知视图控制器模型数据已更改,并且必须反映该更改)。这些包括:


使用委托。这可能是我在这里列出的最糟糕的方法,因为如果您想告诉多个对象有关模型数据更改的信息,则必须有多个委托(或它们的一个数组)。这对代表的使用很差。
viewDidAppear上重新加载。如果仅要确保视图控制器更新其视图以反映在另一个视图控制器上更改的数据,则可以在视图再次出现时刷新视图。这是最原始的解决方案,并且仅当您正在处理视图控制器(例如,已更改数据的模态视图被取消后重新出现)时才起作用。在那些简单的情况下,这通常是最简单的解决方案。

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self updateField1Label];
    [self updateField2Label];
    [self.tableView reloadData];
}

Register for notifications通过NSNotificationCenter。这样做的好处是,多个对象可以将自己添加为同一通知的观察者。例如,在.m文件中为您的通知定义密钥:

NSString * const kNotificationField1Changed = @"com.log139.field1";


然后,在.h文件中定义对该键的外部引用:

extern NSString * const kNotificationField1Changed;


然后,希望收到更改通知的对象可以注册该通知:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(handleField1Notification:)
                                             name:kNotificationField1Changed
                                           object:nil];


显然,您必须编写“ handler”方法:

- (void)handleField1Notification:(NSNotification*)notification
{
    self.field1Label.text = self.model.name;
}


最后,该模型字段的任何更新都可以发布通知,例如:

- (void)saveAndPop:(UITextField *)textField
{
    self.model.field1 = textField.text;

    [[NSNotificationCenter defaultCenter] postNotificationName:kNotificationField1Changed
                                                        object:self
                                                      userInfo:nil];

    [self.navigationController popViewControllerAnimated:YES];
}


如果这样做,您只需要确保在为通知注册的对象超出范围时,它还必须为该通知取消注册:

[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:kNotificationField1Changed
                                              object:nil];

使用key value observing。同样,多个对象可以注册成为模型属性的观察者。假设您已经为@property对象定义了三个属性(通过Model)。任何想要通知更改的对象都可以将自己添加为这些属性的观察者,例如:

[self.model addObserver:self forKeyPath:@"field1" options:0 context:NULL];
[self.model addObserver:self forKeyPath:@"field2" options:0 context:NULL];
[self.model addObserver:self forKeyPath:@"field3" options:0 context:NULL];


然后,您只需要编写一个observeValueForKeyPath方法:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"field1"])
        [self updateField1Label];

    else if ([keyPath isEqualToString:@"field2"])
        [self updateField2Label];

    else if ([keyPath isEqualToString:@"field3"])
        [self.field3TableView reloadData];
}


唯一棘手的是,如果对象之一是集合(例如NSMutableArray),则必须编写collection accessors。有关更多示例,请参见该文档。但是,例如,我有一个模型,该模型的属性是宠物名NSMutableArray *petNames的数组。因此,我必须为模型编写以下两种方法:

- (void)insertObject:(NSString *)petName inPetNamesAtIndex:(NSUInteger)index
{
    [self.petNames insertObject:petName atIndex:index];
}

- (void)removeObjectFromPetNamesAtIndex:(NSUInteger)index
{
    [self.petNames removeObjectAtIndex:index];
}


而且我不再调用[self.model.petNames addObject:aPetName],而是调用了[self.model insertObject:aPetName inPetNamesAtIndex:0];(并且这样做会自动进行通知)。


简而言之,如果您需要通知多个对象模型数据的变化,那么我认为键值观察是最优雅的方法,但是如果要处理,则需要花费一些时间来解决这个问题。集合。我认为仅发布通知是相对简单的选择。



参考文献:


可可核心竞争力中的Model View Controller
《 Objective-C编程中的概念》中的Model View Controller
Key Value Observing Programming Guide
Key Value Coding Programming Guide
如果您要使用KVC处理集合,请特别注意“键值编码编程指南”中的Collection Accessor Patterns for To-Many Properties部分。

关于ios - 协议(protocol)类别和传递信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14878357/

相关文章:

testing - 网络协议(protocol)测试

java - Protobuf/ Protocol Buffer - IndexOutOfBoundsException

ios - 为什么 UITableViewAutomaticDimension 不起作用?

ios - 使用现有应用名称发布新应用?

objective-c - 如何让 NSWindow 在没有焦点的情况下处理 mouseDown 事件?

ios - 重新加载 tableView - Objective C

ios - swift 中 java 接口(interface)或 objective c 协议(protocol)的等价物是什么?

ios - UIScrollView 内部一致性崩溃

ios - 等到第一个异步函数完成后再执行第二个异步函数

objective-c - 使用 UITabBar 在 TableView 中选择行时无法显示详细信息 View