GCD 和 OSSpinLockLock
GCD and OSSpinLockLock
我可能会以错误的方式提问,并冒着被 Whosebug 完全阻止的风险。我有阿斯伯格综合症,没有社交技能,所以我很抱歉问我最后一个(?)问题(因为像这样的系统只为没有障碍的人设计)。
我正在使用 GCD 从 Instagram 加载图像和视频。我在一个用户界面非常 'busy' 的应用程序中执行此操作,我想保持 运行 流畅,所以我在后台加载 Instagram 媒体。
下面的代码(我可能格式有误,所以我先道歉)工作正常并且确实是我想要它做的。它在后台加载图像(为了简单起见,我将视频放在外面),我的主要 UI 是图像加载时的响应。我在负载之间显示它们,并且也可以正常工作。
但是
10 分钟后,有时是 20 分钟,有时是 30 分钟,有时甚至是两个小时后,我的应用程序得到 OSSpinLockLock 冻结。如果我删除下面的代码,我将看不到任何媒体,但应用程序永远不会冻结。
我已经在网上搜索了几天关于完成这项工作的替代方法,并找到了 OSSpinLockLock 的解释。没运气。我唯一发现的是使用 GCD 不会导致 OSSpinLockLock。我已经使用了我所有的仪器知识(我必须承认它比我想象的要有限),但我找不到错误。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^(void) {
[[InstagramEngine sharedEngine] getMediaAtLocation:location count:kInstagramLocationBufferSize maxId:nil withSuccess:^(NSArray* media, InstagramPaginationInfo* paginationInfo) {
if (media && media.count>0) {
for (InstagramMedia* mediaObject in media) {
NSData* data = [[NSData alloc] initWithContentsOfURL:mediaObject.standardResolutionImageURL];
if (data) {
UIImage* img = [UIImage imageWithData:data];
if (img)
[self.locationBuffer addObject:img];
data = nil;
}
}
}
} failure:^(NSError *error) {
;
}];
});
如果您查看这段代码,您是否看到任何可能导致该锁定的内容?因为我绝对不会。
self.locationBuffer 在.h 中声明为
@property (nonatomic,strong) NSMutableArray* locationBuffer;
并且被正确分配和初始化(否则问题是什么就很清楚了)。我也尝试过不将 UIImage 而是 NSData 放入数组中,但这没有任何区别。
例如,在我的 iPad 迷你视网膜上,CPU-负载达到 195% 并在该数字附近停留了很长时间。最终,有时会在几个小时后,应用程序崩溃。
非常欢迎任何建议。
编辑:正如我现在在 iPad 本身的 ips 文件中看到的那样(由于某些神秘原因我无法粘贴到此网页(Whosebug 是否仍处于实验阶段?))我看到了iPad 确实在 NSURLConnection 上花费了 16.000+ 秒...
我的难处是某些超时或故障会阻塞您的 gcd 队列太多时间。尝试用 NSOperationQueue
重写该代码,这样你就可以在错误或 view/controller 消失时停止队列。
更新 1:
这是我对你的代码的试用,我添加了队列和日志,检查它们并检查超时值。这样,如果请求没有完成(很可能),您可以跟踪它。所有请求都是连续的,因此如果其中一个请求停止,您应该立即注意到它。
您可以创建多个队列并按顺序访问它们(循环法)以同时处理更多请求。我不会使用超过 4 个队列,这也是大多数桌面互联网浏览器的默认设置。
// keep the same queue for all request (class member?), don't put it in the same block
NSOperationQueue* queue= [[NSOperationQueue alloc] init];
// keep this in another code block from queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
[[InstagramEngine sharedEngine] getMediaAtLocation:location count:kInstagramLocationBufferSize maxId:nil withSuccess:^(NSArray* media, InstagramPaginationInfo* paginationInfo) {
if (media && media.count>0) {
for (InstagramMedia* mediaObject in media) {
NSURL* url= mediaObject.standardResolutionImageURL;
NSLog(@"Start loading from %@", url);
NSURLRequest* req= [NSURLRequest requestWithURL:mediaObject.standardResolutionImageURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30]; // 30 seconds timeout
[NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"Stop loading from %@ %@ %@", url, response, connectionError);
if (data != nil && connectionError == nil) {
UIImage* img = [UIImage imageWithData:data];
if (img) {
// if you are triggering some ui update run on main thread
// [self.locationBuffer addObject:img];
[self.locationBuffer performSelectorOnMainThread:@selector(addObject:)
withObject:img
waitUntilDone:NO];
}
}
}];
}
}
} failure:^(NSError *error) {
NSLog(@"Error getting media list: %@", error);
}];
});
OSSpinLocks 在 iOS8.3+ 上有错误:report
, 这会导致这种冻结。
我认为您应该用其他东西替换 OSSpinLocks 以在您的应用程序中解决此问题(也许创建您自己的自旋锁实现 - 在 SO 中搜索 OSSpinLock)。
我可能会以错误的方式提问,并冒着被 Whosebug 完全阻止的风险。我有阿斯伯格综合症,没有社交技能,所以我很抱歉问我最后一个(?)问题(因为像这样的系统只为没有障碍的人设计)。
我正在使用 GCD 从 Instagram 加载图像和视频。我在一个用户界面非常 'busy' 的应用程序中执行此操作,我想保持 运行 流畅,所以我在后台加载 Instagram 媒体。
下面的代码(我可能格式有误,所以我先道歉)工作正常并且确实是我想要它做的。它在后台加载图像(为了简单起见,我将视频放在外面),我的主要 UI 是图像加载时的响应。我在负载之间显示它们,并且也可以正常工作。
但是
10 分钟后,有时是 20 分钟,有时是 30 分钟,有时甚至是两个小时后,我的应用程序得到 OSSpinLockLock 冻结。如果我删除下面的代码,我将看不到任何媒体,但应用程序永远不会冻结。
我已经在网上搜索了几天关于完成这项工作的替代方法,并找到了 OSSpinLockLock 的解释。没运气。我唯一发现的是使用 GCD 不会导致 OSSpinLockLock。我已经使用了我所有的仪器知识(我必须承认它比我想象的要有限),但我找不到错误。
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^(void) {
[[InstagramEngine sharedEngine] getMediaAtLocation:location count:kInstagramLocationBufferSize maxId:nil withSuccess:^(NSArray* media, InstagramPaginationInfo* paginationInfo) {
if (media && media.count>0) {
for (InstagramMedia* mediaObject in media) {
NSData* data = [[NSData alloc] initWithContentsOfURL:mediaObject.standardResolutionImageURL];
if (data) {
UIImage* img = [UIImage imageWithData:data];
if (img)
[self.locationBuffer addObject:img];
data = nil;
}
}
}
} failure:^(NSError *error) {
;
}];
});
如果您查看这段代码,您是否看到任何可能导致该锁定的内容?因为我绝对不会。
self.locationBuffer 在.h 中声明为
@property (nonatomic,strong) NSMutableArray* locationBuffer;
并且被正确分配和初始化(否则问题是什么就很清楚了)。我也尝试过不将 UIImage 而是 NSData 放入数组中,但这没有任何区别。
例如,在我的 iPad 迷你视网膜上,CPU-负载达到 195% 并在该数字附近停留了很长时间。最终,有时会在几个小时后,应用程序崩溃。
非常欢迎任何建议。
编辑:正如我现在在 iPad 本身的 ips 文件中看到的那样(由于某些神秘原因我无法粘贴到此网页(Whosebug 是否仍处于实验阶段?))我看到了iPad 确实在 NSURLConnection 上花费了 16.000+ 秒...
我的难处是某些超时或故障会阻塞您的 gcd 队列太多时间。尝试用 NSOperationQueue
重写该代码,这样你就可以在错误或 view/controller 消失时停止队列。
更新 1:
这是我对你的代码的试用,我添加了队列和日志,检查它们并检查超时值。这样,如果请求没有完成(很可能),您可以跟踪它。所有请求都是连续的,因此如果其中一个请求停止,您应该立即注意到它。 您可以创建多个队列并按顺序访问它们(循环法)以同时处理更多请求。我不会使用超过 4 个队列,这也是大多数桌面互联网浏览器的默认设置。
// keep the same queue for all request (class member?), don't put it in the same block
NSOperationQueue* queue= [[NSOperationQueue alloc] init];
// keep this in another code block from queue
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^(void) {
[[InstagramEngine sharedEngine] getMediaAtLocation:location count:kInstagramLocationBufferSize maxId:nil withSuccess:^(NSArray* media, InstagramPaginationInfo* paginationInfo) {
if (media && media.count>0) {
for (InstagramMedia* mediaObject in media) {
NSURL* url= mediaObject.standardResolutionImageURL;
NSLog(@"Start loading from %@", url);
NSURLRequest* req= [NSURLRequest requestWithURL:mediaObject.standardResolutionImageURL
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:30]; // 30 seconds timeout
[NSURLConnection sendAsynchronousRequest:req queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSLog(@"Stop loading from %@ %@ %@", url, response, connectionError);
if (data != nil && connectionError == nil) {
UIImage* img = [UIImage imageWithData:data];
if (img) {
// if you are triggering some ui update run on main thread
// [self.locationBuffer addObject:img];
[self.locationBuffer performSelectorOnMainThread:@selector(addObject:)
withObject:img
waitUntilDone:NO];
}
}
}];
}
}
} failure:^(NSError *error) {
NSLog(@"Error getting media list: %@", error);
}];
});
OSSpinLocks 在 iOS8.3+ 上有错误:report
, 这会导致这种冻结。
我认为您应该用其他东西替换 OSSpinLocks 以在您的应用程序中解决此问题(也许创建您自己的自旋锁实现 - 在 SO 中搜索 OSSpinLock)。