Ios 带有+;(NSArray)

Ios 带有+;(NSArray),ios,cocoa-touch,nsarray,nsobject,Ios,Cocoa Touch,Nsarray,Nsobject,我正在创建一个NSObject来加载时间线twitter 代码: …可以…但我必须添加一个帐户(另一个视图)。由于它是一个+(NSArray*),所以它不能识别my(ACAccount)或同步性之外的任何对象 在开始讨论您要问的问题之前,非常值得详细讨论@Martin提到的内容:方法-[account performRequestWithHandler::是异步的 从正在执行代码的线程调用方法会导致某些活动在第二个后台启动。同时,在第一个线程上继续执行(执行performRequestWithH

我正在创建一个NSObject来加载时间线twitter 代码:

…可以…但我必须添加一个帐户(另一个视图)。由于它是一个+(NSArray*),所以它不能识别my(ACAccount)或同步性之外的任何对象 在开始讨论您要问的问题之前,非常值得详细讨论@Martin提到的内容:方法
-[account performRequestWithHandler::
是异步的

从正在执行代码的线程调用方法会导致某些活动在第二个后台启动。同时,在第一个线程上继续执行(执行
performRequestWithHandler:
executeTweetRequest
的线程)。调用
executeTweetRequest
后的某个不确定时间段,调用作为唯一参数传递给
-[account performRequestWithHandler:
的块

因此,您将无法从
executeTweetRequest
同步返回tweet数组

最时髦的方法是将方法更改为基于块:

+ (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block
{
    NSURL *getTweetUrl = [NSURL URLWithString:@"http://api.twitter.com/1.1/statuses/home_timeline.json"];
    SLRequest *tweetRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter
                                                 requestMethod:SLRequestMethodGET
                                                           URL:getTweetUrl
                                                    parameters:nil];
    tweetRequest.account = //...this will be addressed in a moment
    [tweetRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        if ([urlResponse statusCode] == 200) {
            NSError *jsonParsingError = nil;
            NSArray *fetchedTweets = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonParsingError];
            block(fetchedTweets, jsonParsingError);
        }
    }];
}
当从第二个
UITableViewController
子类调用
fetchTweetsWithCompletion:
时,您将传入一个块,可能类似于以下内容:

- (void)viewDidLoad
{
    //...
    [TwitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
}
此代码的结果是,一旦后台队列上的tweets获取完成,表视图控制器的属性
tweets
将设置为获取的结果,并且其表视图将重新加载其数据

范围(解决问题) 你所描述的问题

因为它是一个+(NSArray*),所以它不能识别my(ACAccount)或外部的任何对象

就是你不能从你的类方法
+[TwitterWrapper ExecuteTweetFeetFetch]
中访问你的类的任何实例的实例变量(为了方便,我称它为
TwitterWrapper
)。这里的问题是其中之一。(因此,多亏了,问题还在于内存管理。)

我们的目标是将
ACAccount
的实例隐藏在第一个表视图控制器的某个位置,并从第二个表视图控制器访问该实例

有几种方法可以做到这一点:

使用全局变量 最糟糕的是使用可怕的:

在TwitterWrapper.h中,您将声明twitter的
extern
帐户:

//TwitterWrapper.h

extern ACAccount *twitterAccount;

@interface TwitterWrapper : executeTweetFetch
+ (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block;
@end
TwitterWrapper.m
中,您将定义
twitterAccount
,使其具有全局范围(例如,在
@实现之前
块:

ACAccount *twitterAccount;

@implementation TwitterWrapper
//...
@end
在类方法的定义中,您应该

+ (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block
{
    //...
    tweetRequest.account = twitterAccount;
    //...
}
注意:这种方法非常不时尚,更不用说完全危险了。在这种情况下,避免这种方法当然是可能的


接下来的两种方法都涉及将
fetchTweetsWithCompletion:
更改为实例方法,并将
acacaccount
属性添加到
TwitterWrapper

@interface TwitterWrapper : NSObject
@property (nonatomic) ACAccount *account;
- (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block;
@end
@implementation TwitterWrapper

- (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block
{
    //...
    twitterRequest.account = self.account;
    //...
}

@end
@实现
如下所示

@interface TwitterWrapper : NSObject
@property (nonatomic) ACAccount *account;
- (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block;
@end
@implementation TwitterWrapper

- (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block
{
    //...
    twitterRequest.account = self.account;
    //...
}

@end
使用共享实例 在这种情况下,第二种最糟糕的方法是使用TwitterWrapper的共享实例。这涉及到向类中添加一个类方法(称为类似于
+SharedRapper
)的聪明方法:

@interface TwitterWrapper : NSObject
+ (TwitterWrapper *)sharedWrapper;
@property (nonatomic) ACAccount *account;
- (void)fetchTweetsWithCompletion:(void (^)(NSArray *, NSError *))block;
@end
并使用的来初始化:

此时,您有了一个TwitterWrapper的实例,您可以将第一个表视图控制器中的
ACAccount的实例存储到该实例中,并从第二个表视图控制器中使用(通过
self.account
-fetchTweetsWithCompletion:
的实现中使用):

在第一个
UITableViewController
子类中的某个地方

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
然后,在第二个
UITableViewController
子类中(可能在
-viewDidLoad
中),您将

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
但是,此解决方案与使用全局变量非常相似(区别在于全局变量的创建是线程安全的)

传递TwitterWrapper的实例 更好的解决方案是将
TwitterWrapper
的实例从第一个表视图控制器传递到第二个表视图控制器

注意:为简洁起见,我假设在用户选择第一个表视图控制器中的帐户行后,第二个表视图控制器立即变为活动状态

为此,您需要添加一个属性

@property (nonatomic) TwitterWrapper *twitterWrapper;
到第二个
UITableViewController
子类

在第一个表视图控制器中的某个位置

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
然后,在第二个
UITableViewController
子类中(可能在
-viewDidLoad
中),您将

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
传递account的一个实例 与其在第二个
UITableViewController
子类实例上存储
TwitterWrapper
的实例,最好的解决方案是存储
acacaccount
的实例,并更改
TwitterWrapper
的接口以再次获取tweet

在这种情况下,我们希望fetch方法再次成为类方法。正如@MartinR所建议的,向fetch方法添加account参数:

+ (void)fetchTweetsWithAccount:(ACAccount *)theAccount completion:(void (^)(NSArray *, NSError *))block
{
    NSURL *getTweetUrl = [NSURL URLWithString:@"http://api.twitter.com/1.1/statuses/home_timeline.json"];
    SLRequest *tweetRequest = [SLRequest requestForServiceType:SLServiceTypeTwitter
                                                 requestMethod:SLRequestMethodGET
                                                           URL:getTweetUrl
                                                    parameters:nil];
    tweetRequest.account = theAccount;
    [tweetRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        if ([urlResponse statusCode] == 200) {
            NSError *jsonParsingError = nil;
            NSArray *fetchedTweets = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonParsingError];
            block(fetchedTweets, jsonParsingError);
        }
    }];
}
接下来,将类型为
ACAccount
的属性添加到第二个
UITableViewController
子类:

@property (nonatomic) ACAccount *account;
然后,在第一个表视图控制器中的某个地方

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
然后,在第二个
UITableViewController
子类中(可能在
-viewDidLoad
中),您将

//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
[[TwitterWrapper sharedWrapper] setAccount:theAccount];
//...
    //...
    [[TwitterWrapper sharedWrapper] fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = //this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
TwitterWrapper *theTwitterWrapper = [[TwitterWrapper alloc] init];
twitterWrapper.account = theAccount;
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.twitterWrapper = theTwitterWrapper;
//...    
    //...
    [self.twitterWrapper fetchTweetsWithCompletion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...
//...
ACAccount *theAccount = ////this is initialized somehow within this class (the first UITableViewController subclass), probably by the selection of a row
SecondTableViewController *tweetsTableViewController = //initialize the table view controller
tweetsTableViewController.account = theAccount;
//...    
    //...
    [TwitterWrapper fetchTweetsWithAccount:self.account completion:^(NSArray *tweets, NSError *error) {
        if (tweets) {
            self.tweets = tweets;
            [self.tableView reloadData];
        } else if (error) {
            //present a UIAlertView, perhaps...
        }
    }];
    //...

“我必须添加一个ACAccount(另一个视图)”是什么意思?编辑…用户在其他视图(TableView)中选择一个帐户为什么不添加另一个参数:
+(NSArray*)executeweetfetchforaccount:(ACAccount*)account
?-但是