IOS阻止ui线程,直到singleton类中的JSON解析函数完成
我正在制作一个IOS应用程序,它应该在启动时从json提要收集数据。基本上,初始视图控制器是一个加载屏幕。在后台,在加载屏幕期间,它应该实例化我的singleton类,并调用json提要来用对象填充数组。当这个过程完成后,它会自动切换到我的主菜单 奇怪的是。我已经设置好了,效果很好,但5次中只有4次。有时它会直接进入菜单,在后台加载提要,这不是我想要的 有人能找到罪犯吗 以下是加载屏幕的我的视图控制器:IOS阻止ui线程,直到singleton类中的JSON解析函数完成,ios,objective-c,xcode,afnetworking,blocking,Ios,Objective C,Xcode,Afnetworking,Blocking,我正在制作一个IOS应用程序,它应该在启动时从json提要收集数据。基本上,初始视图控制器是一个加载屏幕。在后台,在加载屏幕期间,它应该实例化我的singleton类,并调用json提要来用对象填充数组。当这个过程完成后,它会自动切换到我的主菜单 奇怪的是。我已经设置好了,效果很好,但5次中只有4次。有时它会直接进入菜单,在后台加载提要,这不是我想要的 有人能找到罪犯吗 以下是加载屏幕的我的视图控制器: #import "loadingViewController.h" #import "Sin
#import "loadingViewController.h"
#import "Singleton.h"
#import "MBProgressHUD.h"
@interface loadingViewController ()
@end
@implementation loadingViewController
- (void)viewDidLoad {
[super viewDidLoad];
//[self performSegueWithIdentifier:@"launchSegue" sender:self];
// Do any additional setup after loading the view.
}
- (void)viewWillAppear:(BOOL)animated {
Singleton *singletonManager = [Singleton singletonManager];
[singletonManager loadJsonData];
}
- (void)viewDidAppear:(BOOL)animated {
[self performSegueWithIdentifier:@"launchSegue" sender:self];
}
- (void)doSegue
{
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAll;
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
这是我在singleton类中的实现:
implementation Singleton
@synthesize acts;
#pragma mark Singleton Methods
+ (id)singletonManager {
static Singleton *singletonMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonMyManager = [[self alloc] init];
});
return singletonMyManager;
}
- (id)init {
if (self = [super init]) {
//someProperty = [[NSString alloc] initWithString:@"Default Property Value"];
self.acts = [[NSMutableArray alloc] init];
}
return self;
}
- (BOOL) loadJsonData
{
NSString *urlString = @"http://wwww.paaspop.nl/json/gettimetable";
NSString *callback = @"api";
NSDictionary *parameters = @{@"callback": callback};
AFHTTPRequestOperationManager* manager = [AFHTTPRequestOperationManager manager];
manager.securityPolicy.allowInvalidCertificates = YES;
manager.responseSerializer = [CDLJSONPResponseSerializer serializerWithCallback:callback];
__block NSDictionary* response = nil;
AFHTTPRequestOperation* operation = [manager
GET: urlString
parameters: parameters
success:^(AFHTTPRequestOperation* operation, id responseObject){
response = responseObject;
[self parseJSONData:response];
}
failure:^(AFHTTPRequestOperation* operation, NSError* error){
NSLog(@"Error: %@", error);}
];
[operation waitUntilFinished];
return true;
}
-(void) parseJSONData:(id) JSON
{
NSArray *allActs = [JSON objectForKey:@"acts"];
for (NSDictionary* dict in allActs) {
//Create a pirate object where the json data can be stored
Act *act = [[Act alloc] init];
NSString *url;
//Get the JSON data from the dictionary and store it at the Pirate object
act.title = [dict objectForKey:@"title"];
act.subtitle = [dict objectForKey:@"add"];
act.jsontitle = [dict objectForKey:@"url_title"];
act.favorite = FALSE;
url = [dict objectForKey:@"photo"];
NSURL *imageURL = [NSURL URLWithString:[dict objectForKey:@"photo"]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
act.photo = [self imageWithImage:[UIImage imageWithData:imageData] scaledToWidth:320];
NSLog(@"%f, %f",act.photo.size.width,act.photo.size.height);
//Add the pirates to the array
[self.acts addObject:act];
}
}
-(UIImage*)imageWithImage: (UIImage*) sourceImage scaledToWidth: (float) i_width
{
float oldWidth = sourceImage.size.width;
float scaleFactor = i_width / oldWidth;
float newHeight = sourceImage.size.height * scaleFactor;
float newWidth = oldWidth * scaleFactor;
UIGraphicsBeginImageContext(CGSizeMake(newWidth, newHeight));
[sourceImage drawInRect:CGRectMake(0, 0, newWidth, newHeight)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (NSMutableArray *) getActs {
return self.acts;
}
- (void)dealloc {
// Should never be called, but just here for clarity really.
}
我认为最好的方法是让-voidloadJsonData函数接受一个块,该块将在解析操作完成时执行。该块可以包含执行一个序列的代码。如果您发现块很难使用,我认为您可以使用通知中心执行此任务 你发布这样的通知
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationName" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(methodCalledWhenReady:)
name:@"notificationName"
object:nil];
-(void) methodCalledWhenReady: (NSNotification *) notification
{
//this is where you place the code that you want to execute only after
you finished fetching the data in the singleton class, in your case:
[self performSegueWithIdentifier:@"launchSegue" sender:self];
}
在parseJSONData方法中的for循环之后
在主视图控制器中,应在viewDidLoad中添加一个观察者,如下所示
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationName" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(methodCalledWhenReady:)
name:@"notificationName"
object:nil];
-(void) methodCalledWhenReady: (NSNotification *) notification
{
//this is where you place the code that you want to execute only after
you finished fetching the data in the singleton class, in your case:
[self performSegueWithIdentifier:@"launchSegue" sender:self];
}
之后,您只需在主视图控制器中创建名为Henready的方法,该方法接收NSNotificationObjects,在这种情况下您并不真正需要它
[[NSNotificationCenter defaultCenter] postNotificationName:@"notificationName" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(methodCalledWhenReady:)
name:@"notificationName"
object:nil];
-(void) methodCalledWhenReady: (NSNotification *) notification
{
//this is where you place the code that you want to execute only after
you finished fetching the data in the singleton class, in your case:
[self performSegueWithIdentifier:@"launchSegue" sender:self];
}
您应该查看有关通知的更多信息
希望这有帮助 这里没有任何东西可以阻止它直接进入新屏幕。事实上,它每5次工作1次,其他4次都很奇怪 您已将MBProgressHud包含在文件中,但您没有对其执行任何操作。最好让用户界面保持活动状态,然后阻止用户进行操作,让应用程序看起来没有响应能力 在下载类中,您依赖waitUntilFinished。这将等待网络操作完成,然后返回。这不是等待json解析和图像操作发生
AFHTTPRequest库非常过时。这是一个很好的工作,但除非你有一些非常具体的较低层次的需要,它是远远涉及。NSUrlSession是苹果公司推出的一款新工具,功能强大,使用极其简单。我认为NSNotifications很难调试,最好限制在许多未知收件人需要处理事件的情况下。我认为最好是a使用Aris的答案中的完成块,或者b创建一个简单的@protocol,并将视图控制器本身设置为singleton类的委托,以便在加载JSON数据时从该协议调用方法。