Objective c Can';t从SLRequest块内部更改块变量
我试图更改块中int的值。(在这个代码示例中,SLRequest本身只是我的完整应用程序的上下文设置,在这里不起作用——只需编译并运行ok,这样我就可以测试设置int。要编译这个示例,需要在项目中包含Socialframework。输出包含在下面。) 请注意,输出行的顺序不一致。它在执行中间命令之前开始和结束。我怎样才能解决这个问题?我只想改变那个位置的int值,让它在块外使用 ==更新=== 我在网上找到了这个问题的多个相切的版本,但形式不符合我的目的。所以也许我提出的问题无法回答。让我尝试添加一些上下文 我的应用程序正在收集来自Twitter指定的不同类型的多个Twitter API调用的数据。我不是为了展示而建桌子。我只需要IVAR中的数据,并最终管理对象。除了获取Twitter数据,该应用程序还有很多工作要做,因此我不想将太多的应用程序结构放在单个performRequestWithHandler块中,以便在某个时候访问其返回的数据。对我来说,从网上获取数据是一种实用操作,而不是应用程序设计的唯一决定因素。我的一些API调用具体取决于从先前以特定顺序执行的其他类型的API调用中收集的数据 我需要知道以前的调用何时完成,以便使用从它们的数据对象设置的ivar值 也就是说,我需要一种方法来进行API调用#1,将各种返回数据分配给IVAR,在performRequestWithHandler块之外对IVAR执行其他操作,根据调用#1和随后返回的API调用进行API调用#2和#3等,并最终切换到其他ViewController,以各种方式显示来自多个API调用返回值的已处理数据 我完全明白performRequestWithHandler是在一个未指定的线程上执行的,我不知道什么时候执行。我不担心由于同步网络访问延迟而导致的UI长时间等待,因为我打算指定非常短的等待时间。我不会让我的用户坐在那里等待缓慢的网络连接!如果连接速度慢,我将短暂显示活动指示器,并放弃快速等待显示警报。应用程序的这一部分不是我在这里所面临的重点挑战 我的挑战是在部分或全部调用完成后,将来自多个performRequestWithHandler调用的返回数据组装到一个位置 在我看来,performRequestWithHandler调用的级别可能太高,无法实现我需要的同步控制和数据访问。我不知道 上面的代码示例只是我所能想到的用简单的编译方式隔离和演示问题的最简单方法。我尝试过许多变体,但到目前为止没有乐趣 希望这有助于澄清我的设计理念Objective c Can';t从SLRequest块内部更改块变量,objective-c,xcode,scope,objective-c-blocks,block,Objective C,Xcode,Scope,Objective C Blocks,Block,我试图更改块中int的值。(在这个代码示例中,SLRequest本身只是我的完整应用程序的上下文设置,在这里不起作用——只需编译并运行ok,这样我就可以测试设置int。要编译这个示例,需要在项目中包含Socialframework。输出包含在下面。) 请注意,输出行的顺序不一致。它在执行中间命令之前开始和结束。我怎样才能解决这个问题?我只想改变那个位置的int值,让它在块外使用 ==更新=== 我在网上找到了这个问题的多个相切的版本,但形式不符合我的目的。所以也许我提出的问题无法回答。让我尝试添
感谢您提供的任何具体帮助、线索或想法。在这一点上,一个极小的工作代码示例将是天赐良机,但如果/当我找到一个解决方案时,我将继续工作并发布一个解决方案。我认为您已经回答了自己的问题,正如您所看到的,您正在读取块变量(两次),甚至在块执行之前 这是您正在调用的异步方法。它将在
viewDidLoad
返回后的某个时间完成。因此,日志输出完全没有顺序错误。你所看到的是这些电话的实际情况
您应该考虑您的设计,并意识到此请求可能需要很长时间才能完成,特别是当用户处于慢速网络上时,等等。因此,您需要决定在请求执行期间向用户呈现什么,然后在请求最终完成时如何更新用户
编辑
从你的评论中,让我试着给你一个小例子,希望能让你摆脱困境。我不一定要在这里为您编写一个完整的工作示例,它考虑了所有可能的并发性、内存管理和设计含义。但是,一个简单的开始方法是安排一个只更新视图控制器上某些属性的块(假设视图控制器的长度足以使请求完成或失败!)
我希望这能为你指明正确的方向。除此之外,我建议有很多好的课程(免费和付费),可以帮助你理解这些对移动开发非常重要的基本概念(在Android或iOS上)。在移动设备上处理异步方法和事件是除“hello world”之外的任何事情的现实
另一次编辑
我看到你对问题的新编辑。这确实有助于解释这里的上下文。如果您有很多不同的异步调用发生,那么您可能希望将其从视图控制器中取出,放入执行所有这些工作并汇编结果的数据控制器中。在这种情况下,同样的基本原则也适用,你只需要考虑更多的调用和更多的排序。我想你已经回答了你自己的问题,正如你所看到的,你正在读取块变量(两次),甚至在块执行之前 这是您正在调用的异步方法。它将在
viewDidLoad
返回后的某个时间完成。因此,日志输出完全没有顺序错误。你所看到的是这些电话的实际情况
您应该考虑一下您的设计,并意识到此请求可能需要很长时间才能完成,尤其是当用户处于慢速网络等情况下。因此,您需要决定在
#import "MainViewController.h"
#import <Social/Social.h>
@interface MainViewController ()
@end
@implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// This SLRequest stuff is just to provide the context for the block in question below
NSString * theURLstr = @"http://someurl";
NSURL * theNSURL = [[NSURL alloc] initWithString:theURLstr];
SLRequest *theRequest = [SLRequest requestForServiceType: SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:theNSURL parameters:nil];
[theRequest setAccount:nil]; //
// This is our test value. We expect to be able to change it inside the following block
__block int test = 44;
NSLog(@"(BEFORE block) test is: %d", test);
[theRequest performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
{
// We get here late.
test = 27;
NSLog(@"(INSIDE block) test is: %d", test);
}];
// We get here fine, but test isn't changed
NSLog(@"(AFTER block) test is: %d", test);
}
2013-02-10 19:13:53.283 debugExp1[92743:c07] (BEFORE block) test is: 44
2013-02-10 19:13:53.285 debugExp1[92743:c07] (AFTER block) test is: 44
2013-02-10 19:13:53.312 debugExp1[92743:1303] (INSIDE block) test is: 27
[theRequest performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
{
int test = 27;
NSLog(@"(INSIDE block) test is: %d", test);
// now schedule a block on the main queue which will update our UI with this
// new data "27"
dispatch_async(dispatch_get_main_queue(), ^{
// here we are on the main queue, ready to read our test and do something with it.
NSLog(@"(updating the UI) test is: %d", test);
// now that we know we can read the data, we can save that data, update the UI, do
// whatever is appropriate for your app
// maybe this is as simple as:
self.someProperty = test;
// yes, there is a possible retain cycle here. Worry about that after
// you have the basic mechanics of this understood.
});
}];
- (void)viewDidLoad
{
[super viewDidLoad];
// Test SLRequest wireframe
NSString * theURLstr = @"http://someurl";
NSURL * theNSURL = [[NSURL alloc] initWithString:theURLstr];
SLRequest *theRequest = [SLRequest requestForServiceType: SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:theNSURL parameters:nil];
[theRequest setAccount:nil];
// Set default
self.myNewTestStr = @"default";
NSLog(@"In viewDidLoad, self.myNewTestStr DEFAULT is %@", self.myNewTestStr);
// Listen on "weGotOurValue"
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotOurValue) name:@"weGotOurValue" object:nil];
// [ActivityAlert presentWithText:@"Please wait"];
// Pretend to get some data from the net
[theRequest performRequestWithHandler:
^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error2)
{
// Not sure I need this dispatch, btw
dispatch_async(dispatch_get_main_queue(), ^{
// Change the ivar
self.myNewTestStr = @"changed";
// Post notification "weGotOurValue"
[[NSNotificationCenter defaultCenter] postNotificationName:@"weGotOurValue" object:nil];
// [ActivityAlert dismiss];
});
}];
}
// Called by NSNotificationCenter when it receives
// a postNotificationName:@"weGotOurValue" message
- (void) gotOurValue {
NSLog(@"In gotOurValue, self.myNewTestStr is %@", self.myNewTestStr);
}
2013-02-12 17:44:52.300 debugExp1[5549:c07] In viewDidLoad, self.myNewTestStr DEFAULT is default
2013-02-12 17:44:52.354 debugExp1[5549:c07] In gotOurValue, self.myNewTestStr is changed
// 1
SLRequest *request = [SLRequest
requestForServiceType:SLServiceTypeFacebook
requestMethod:SLRequestMethodGET
URL:[NSURL URLWithString:@"https://graph.facebook.com/me"]
parameters:@{ @"fields" : @"id,first_name,last_name,gender,birthday,email,picture"}];
// 2
request.account = [FacebookController sharedFacebookController].facebookAccount;
// 3
__block NSDictionary *jsonDictD;
[request performRequestWithHandler:^(NSData *responseData,
NSHTTPURLResponse *urlResponse, NSError *error) {
if (error)
{
// 4
[AppHelper showAlertViewWithTag:123 title:APP_NAME message:@"There was an error reading your Facebook account." delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil];
}
else
{
// 5
NSString *decodedString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
// NSLog(@"%@",decodedString);
jsonDictD = [decodedString JSONValue];
NSLog(@"%@",jsonDictD);
if (jsonDictD)
{
[AppHelper saveToUserDefaults:[jsonDictD objectForKey:@"email"] withKey:@"email"];
[AppHelper saveToUserDefaults:[jsonDictD objectForKey:@"id"] withKey:@"facebook_id"];
[userImage setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[[[jsonDictD objectForKey:@"picture"] objectForKey:@"data"] objectForKey:@"url"]]]
placeholderImage:[UIImage imageNamed:@"DefaultPic.png"] success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image)
{
userImage.image=image;
dummyImg=image;
[dummyImg retain];
}
failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error)
{
}];
self.firstNameTextField.text=[jsonDictD objectForKey:@"first_name"];
self.lastNameTextField.text=[jsonDictD objectForKey:@"last_name"];
self.emailTextField.text=[jsonDictD objectForKey:@"email"];
self.dobTextField.text=[jsonDictD objectForKey:@"birthday"];
if ([[jsonDictD objectForKey:@"gender"] isEqualToString:@"male"])
{
gender=@"Male";
}
else
{
gender=@"Female";
}
// [[NSNotificationCenter defaultCenter] postNotificationName:@"Get FB" object:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[[DubitAppDelegate getAppDelegate] hideActivityViewer];
});
}
}
}];