【问题标题】:Sending data from NSObject to UIViewController将数据从 NSObject 发送到 UIViewController
【发布时间】:2012-03-14 23:04:33
【问题描述】:

我已经解决这个问题将近 4 天了。

我认为这不是我的代码的问题,而是导致问题的应用程序的结构。

我正在尝试实现协议和委托以将数组从一个 NSObject(class) 获取到 ViewController。

我的代码几乎是从tutorial 中逐行复制的,唯一的区别在于我打开了 ARC,因此不得不将 (nonatomic, retain) 替换为 (strong) 并且没有使用 dealloc :)

话虽如此,它仍然没有将数据传递回视图控制器。 (非常烦人)我尝试了几十种不同的解决方案组合,我得到了帮助,但没有任何效果。这让我相信我的应用程序的结构或事物的初始化方式等可能存在错误,我现在将尝试解释。

当我的带有 tableview 的 viewcontroller 加载称为我的解析器类的委托的 viewdidload 方法时,一旦加载了 tableview 的第一个单元格,它就会调用我的连接类并告诉它从服务器下载一些数据。 在我的连接类中,我使用来自苹果库的 NSURLConnection 委托,在委托方法 connectionDidFinishLoading 中,已下载的数据被传递给我的解析器类(但是这是我认为它出错的地方,因为我再次声明了对象......我认为这是事情出错的地方)

这就是我从连接类调用解析器类的方式。

parserClass *myparser = [[EngineResponses alloc] init];
[myparser  ReciveResponse:receivedData];

然后,一旦数据在我的解析器类中,它就会被解析,然后我尝试将数据传递给我的视图控制器。但它永远不会访问我设置的委托方法。

希望这就是问题所在,因为我只是不知道还有哪里出错了。 你觉得呢?

更新:这是我的代码 -

ViewController.h

#import "EngineResponses.h" //delegates & protocols

interface SearchViewController : UITableViewController <PassParsedData> {

//delegates to parser class
    EngineResponses *engineResponses;
//..

ViewController.m

#import "EngineResponses.h"

//this is where I set up the delegate/protocol for the parser class
- (void)viewDidLoad
{
    [super viewDidLoad];

//..
engineResponses = [[EngineResponses alloc] init];
[engineResponses setMydelegate:self];
//..
}

//this is where i set up and call the connection class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
if(indexPath.section == 0){        
    //..
    if (indexPath.row == 0){
     EngineRequests *engineRequests = [[EngineRequests alloc] init];
                [engineRequests initalizePacketVariables:0 startCode:@"myReg" activationCode:@"myAct" methodName:@"GetStuff"];
                //..
}

#pragma - Reciver methods

- (void)sendArray:(NSArray *)array
{
    ICMfgFilterArray = array;
    [self.tableView reloadData]; 
}

EngineRequests.m

//connection delegates etc..
//then I pass the data from the connection delegates over to the parser class
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{   
    EngineResponses *engineResponses = [[EngineResponses alloc] init];
    [engineResponses  ReciveResponse:receivedData];
}

EngineResponses.h

@protocol PassParsedData
- (void)sendArray:(NSArray *)array;
@end

//..
id <PassParsedData> mydelegate;
//..
@property (strong) id  <PassParsedData> mydelegate; 

EngineResponses.m

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//..
    [[self mydelegate]sendArray:filteredArray];    
}

1

【问题讨论】:

  • 代码的编辑版本比散文描述更容易诊断。
  • 嗯,你在做类似[myParser setDelegate:myViewController]; 的事情吗?另外,确实需要查看您的代码以提出更好的解决方案。
  • 好的,我已经更新了我的代码.. 抱歉花了这么长时间,只是确保我的一切都完美无缺.. 所以 IMO 我认为错误是我将解析器对象一分为二地方...但我不确定这是否正确或如何解决。
  • 好吧,你的“文件名”和你的类名匹配吗?或者 ParserClass 是您的 EngineResponses 吗?好像是。如果是这样,那么您无缘无故地分配了两次。在 connectionDidFinish 中创建一个新的。现在,它的 mydelegate 最初设置为 nil(我猜)。因此,当您向 mydelegate 发送 sendArray 消息时,该消息为 nil,然后您将消息发送到 nil 对象。这既不会导致编译器错误,也不会导致运行时错误,但它肯定不会执行方法 sendArray。确保您的连接类获得对解析器类对象的引用。
  • 是的,engineRequest 是连接类,engineResponse 是解析器类。这些都是正确的。但为了清楚起见,我只是标记了代码部分。

标签: iphone ios delegates protocols


【解决方案1】:

好的。我会根据你更新的代码重新做。为了方便起见,我复制了您的代码并进行了修改。

ViewController.h

#import "EngineResponses.h" //delegates & protocols

interface SearchViewController : UITableViewController <PassParsedData> {

//delegates to parser class
    EngineResponses *engineResponses;

    EngineRequests *engineRequests;  
//..

说明: 您正在使用 ARC。如果您像以前一样在本地定义指针,并且不 保留它 - 因为 ARC 你不能 - 然后它将在它之后直接释放 创建。您必须至少保留一个对该对象的引用。 请记住,ARC 表示自动引用计数。只要没有 引用将被释放的对象。 这个带有在此处定义的 engineRequests 对象的提议仅在您 一次只提交一个请求。如果您有多个请求,即针对多个单元格或 无论如何,那么您可以选择一个可变数组或可变字典,在您使用它们时保留请求。

ViewController.m

#import "EngineResponses.h"

//this is where I set up the delegate/protocol for the parser class
- (void)viewDidLoad
{
    [super viewDidLoad];

//..
engineResponses = [[EngineResponses alloc] init];
[engineResponses setMydelegate:self];

engineRequests = [[EngineRequests alloc] init];  // Use instance variable instead of local variable
[engineRequests setEnineResponses:engineResponses];

//..
}

//this is where i set up and call the connection class
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
if(indexPath.section == 0){        
    //..
    if (indexPath.row == 0){
     [engineRequests initalizePacketVariables:0 startCode:@"myReg" activationCode:@"myAct" methodName:@"GetStuff"];
                //..
}

#pragma - Reciver methods

- (void)sendArray:(NSArray *)array
{
    ICMfgFilterArray = array;
    [self.tableView reloadData]; 
}

说明:engineRequets 现在是一个实例变量,不应在本地重新定义。 您可以在本地定义一个同名的变量,这将隐藏实例变量。我认为 在这种情况下,您会收到编译器警告,但这会起作用并且很可能会让您感到困惑。 同样,如果您一次使用多个请求,则此解决方案将不起作用!

EngineRequests.h

EngineResponses *engineResponses;

EngineRequests.m

@synthesize engineResponses;

//connection delegates etc..
//then I pass the data from the connection delegates over to the parser class
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{   
    //EngineResponses *engineResponses = [[EngineResponses alloc] init]; //This Object has already been created! 
    [engineResponses  ReciveResponse:receivedData];
}

解释:在这里,对 EngineResponses 的引用现在也是一个实例变量,而不是本地定义的。该对象不会是新创建的,但它会引用在视图控制器中创建的那个对象。这是一个“知道”其视图控制器对象的 EngineResponses,因此可以传回已解析的数据。

EngineResponses.h

@protocol PassParsedData
- (void)sendArray:(NSArray *)array;
@end

//..
id <PassParsedData> mydelegate;
//..
@property (strong) id  <PassParsedData> mydelegate; 

EngineResponses.m

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
//..
    [[self mydelegate]sendArray:filteredArray];    
}

...试一试:)

【讨论】:

  • 不幸的是..根据您的回答,我不太明白我需要在这里做什么。
  • 当我调用 [engineRequests setMydelegate:self];从 cellForRowAtIndexPath 我收到此错误 ** 实例消息的接收方类型 'EngineRequests' 不能声明带有 seclector 'setMyDelegate' 的方法**
  • 嗨,您对 [engineRequests setMydelegate:self]; 说的是 [engineResponses setMydelegate:self]; 还是别的什么意思?因为你说要做的不是锻炼atm。
  • 抱歉,我不得不在某个时间睡觉。无论如何,已经过了午夜。 :)
  • 太棒了 :) 我现在就试一试 :)
【解决方案2】:

始终检查 nil 对象。向 nil 对象发送消息不会执行任何操作,您的应用程序将继续运行。我敢打赌这是问题所在,因为您在各地进行本地分配。为什么不将 receivedata 方法设置为静态方法,因为看起来您不需要这些类来进行一些计算和解析。那么 nil 对象不会是一个因素。

【讨论】:

  • 在 viewController 中有 connectionDidFinisLoading 等工作正常,如果一次只有一个请求“在空中”。如果针对多个表格单元发送单独的请求,那么 C.Johns 的方法会节省很多。
猜你喜欢
  • 2011-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多