我有一个创建ObjectA的视图控制器。然后ObjectA创建ObjectB。 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;
}
答案 0 :(得分:1)
我假设您说这是从您的视图控制器调用的:
myObjectA.delegate = self
您正在从对象A调用以下行:
myObjectB.delegate = self.delegate
从技术上讲,你可以做到这一点,虽然我发现构造有点令人困惑。它甚至有点问题,因为你没有为视图控制器提供任何机制来说'好吧,我不想再成为delegate
&# 34;因为它可能只知道myObjectA
。您没有任何机制让视图控制器告诉myObjectB
它不再想要成为delegate
,因为可能视图控制器甚至没有知道B
的存在。
delegate
的概念是&#34;我想告诉我delegate
某事,或者提出一些要求&#34;。另一方面,如果您的目标是在他们之间共享数据,我倾向于从委托协议模式转移到model-view-controller(MVC)模式,我们&#39 ;专注于&#34;模型&#34;部分:
创建一个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];
显然,你必须写那个&#34; handler&#34;方法:
- (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];
(通过这样做,通知会自动发生)。
简而言之,如果您有多个对象需要通知您的模型数据发生变化,我认为键值观察是最优雅的方法,但需要一点时间来搂着它如果处理集合。我认为只发布通知是一种相对简单的选择。