集合在枚举时发生了变化
我意识到这已被问了很多次,但我只是不知道错误在哪里出现在我的代码中,对于愚蠢而抱歉。集合<CALayerArray:0x1cdb9b90>在枚举时发生了变化
我知道故障是由这种方法:
-(void)getDataFromDatabase {
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
indicator.center = self.view.center;
[indicator bringSubviewToFront:self.view];
[UIApplication sharedApplication].networkActivityIndicatorVisible = TRUE;
[indicator startAnimating];
CGRect screenRect = [[UIScreen mainScreen] bounds];
UIView *overlay = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenRect.size.width, screenRect.size.height)];
overlay.backgroundColor = [UIColor whiteColor];
[self.view addSubview:overlay];
[self.view addSubview:indicator];
NSString *listingurl;
listingurl = [NSString stringWithFormat:@"http://www.herefordshire-tourism-guide.co.uk/app/query.php?getlisting=1&listingname=%@", rowSelectedName];
listingurl = [listingurl stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
NSURL *url = [NSURL URLWithString:listingurl];
NSError *error = nil;
NSStringEncoding encoding;
NSString *jsonreturn = [[NSString alloc] initWithContentsOfURL:url usedEncoding:&encoding
error:&error];
NSData *jsonData = [jsonreturn dataUsingEncoding:NSUTF32BigEndianStringEncoding];
// In "real" code you should surround this with try and catch
NSDictionary * dict = [[CJSONDeserializer deserializer] deserializeAsDictionary:jsonData error:&error];
if (dict)
{
rows = dict[@"listings"];
}
dict = rows[0];
self.photos.font = [UIFont fontWithName:@"ProximaNova-Regular" size:18.0];
self.likes.font = [UIFont fontWithName:@"ProximaNova-Regular" size:18.0];
self.businessName.font = [UIFont fontWithName:@"ProximaNova-Extrabld" size:20.0];
self.address.font = [UIFont fontWithName:@"ProximaNova-Regular" size:16.0];
self.navigationItem.title = dict[@"business"];
NSString *favdb = [NSString stringWithFormat:@"%@", dict[@"favs"]];
if ([favdb isEqualToString:@""]) {
NSString *fav = [NSString stringWithFormat:@"0 Likes"];
self.favourites.text = fav;
} else {
NSString *fav = [NSString stringWithFormat:@"%@ Likes", dict[@"favs"]];
self.favourites.text = fav;
}
if ([favdb isEqualToString:@"1"]) {
NSString *fav = [NSString stringWithFormat:@"1 Like"];
self.favourites.text = fav;
}
self.businessName.text = dict[@"business"];
self.address.text = dict[@"location"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.frame = CGRectMake(140, 85, 40.0, 40.0);
[indicator bringSubviewToFront:self.view];
[indicator startAnimating];
[self.view addSubview:indicator];
UIImage *img = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:dict[@"image1"]]]];
self.image.image = img;
[UIApplication sharedApplication].networkActivityIndicatorVisible = FALSE;
[indicator stopAnimating];
});
listingLoc = [[CLLocation alloc] initWithLatitude:[dict[@"lat"] doubleValue] longitude:[dict[@"lon"] doubleValue]];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
float kilometers = [appDelegate.currentLoc distanceFromLocation:listingLoc]/1000;
int milesint = kilometers * 0.621371192;
NSString *milesOut = [NSString stringWithFormat:@"%i miles", milesint];
self.distance.text = milesOut;
networkImages = [[NSMutableArray alloc] init];
if (dict[@"image1"] != @"") {
[networkImages addObject:dict[@"image1"]];
}
[indicator stopAnimating];
[overlay removeFromSuperview];
}
和IM呼吁在viewWillAppear中方法的方法...
[self performSelectorInBackground:@selector(getDataFromDatabase) withObject:nil];
任何提示,我的代码可能是以次充好,任何帮助都非常感谢!
谢谢。
你在这里有几个问题,主要涉及修改后台线程上的用户界面,你绝对不能这样做。例如:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.frame = CGRectMake(140, 85, 40.0, 40.0);
[indicator bringSubviewToFront:self.view];
[indicator startAnimating];
[self.view addSubview:indicator];
...
在这里,我们修改后台线程当前视图的子视图列表。这不合法。大多数UIKit方法必须在主线程上运行(从GCD的角度来看,这是主队列)。
这条线也是极其危险的内部viewWillAppear:
(或大多数的任何地方):
[self performSelectorInBackground:@selector(getDataFromDatabase) withObject:nil];
你的看法可能出现,并在getDataFromDatabase
消失多次(旁注:你应该把这个fetchDataFromDatabase
“搞定”了可可中的特殊含义)。如果视图出现多次,你可以结束许多线程同时运行,这当然不是你的意思。
你应该几乎从不使用performSelectorInBackground:withObject:
。使用NSOperationQueue
或分派队列来管理后台操作。
我刚开始学习,太复杂了!你可以给我一些代码示例,这样我就可以玩了! – rjg
还没有线索从哪里开始! – rjg
我会开始简单。我在上面的代码中看不到任何需要后台线程的东西。您可以在不产生线程的情况下进行大量的iOS开发。您的主要问题是您已将JSON网络提取集成到视图控制器中。不要这样做。将数据提取放入只管理数据的模型类中(并使用NSURLConnection异步获取数据)。然后视图控制器将响应模型类的变化。请参阅http://developer.apple.com/library/ios/#documentation/general/conceptual/DevPedia-CocoaCore/MVC.html –
这是很多代码。你在哪里迭代数组元素? –
好吧,无论何时你使用UIKit方法进行交互(如上面添加和删除子视图),它必须在主线程上完成,而不是在后台线程中完成,就像你在这里做的那样。 UIKit是**不是线程安全的! – lnafziger