真的很难解决。当用户从他的帐户退出时,我的iOS应用程序(iOS版本6+,Xcode 5.1.1)崩溃了,但只有在它之前被暂停和后台运行时才会崩溃。
这是来自Testflight的崩溃日志:
SIGSEGV
APP_NAME copy__destroy_helper_block_
in CAPServiceManager.m on Line 0
# Binary Image Name Address Symbol
0 APP_NAME copy 0x0010b61c testflight_backtrace
1 APP_NAME copy 0x0010ae5c TFSignalHandler
2 libsystem_platform.dylib 0x33d0087a _sigtramp
3 APP_NAME copy 0x000f180c __destroy_helper_block_ in CAPServiceManager.m on Line 0
4 libsystem_blocks.dylib 0x33bdbae0 _Block_release
5 Foundation 0x27268eb8
6 libobjc.A.dylib 0x33650d5e
7 Foundation 0x272ff372
8 libdispatch.dylib 0x33ba295e
9 libdispatch.dylib 0x33ba5ba6 _dispatch_main_queue_callback_4CF
10 CoreFoundation 0x2655fbd8
11 CoreFoundation 0x2655e2d8
12 CoreFoundation 0x264ac610 CFRunLoopRunSpecific
13 CoreFoundation 0x264ac422 CFRunLoopRunInMode
14 GraphicsServices 0x2da060a8 GSEventRunModal
15 UIKit 0x29bf6484 UIApplicationMain
16 APP_NAME copy 0x0009587a main in main.m on Line 16
17 libdyld.dylib 0x33bc0aae
然而,在Xcode中,它在AppDelegate文件中作为EXC_BAD_ACCESS崩溃。 (没有提供更多细节)。启用NSZombie不起作用,因为它会阻止应用程序在启用时崩溃。
CAPServiceManager中与块相关的代码是:
- (void)executeService:(WCServiceType)service
pin:(NSString *)pin
payLoad:(id)payload
usingBlock:(void (^) (NSError *error))block
{
[self addStartingServiceStatusForService:service];
[[WCWebService sharedWebService]
postAuthTokenForService:service
pin:pin
vehicle:_vehicle
target:self
usingBlock:^(NSError *error, id response) {
if (!error) {
[self executeService:service token:response payLoad:payload usingBlock:block];
}
else {
if (error.code == kWCHTTPStatusCodeUnauthorized) {
_wrongPinCounter++;
}
[self failStartingServiceStatusForServiceType:service error:error serviceAlreadyStarted:NO];
block(error);
}
}];
}
- (void)executeService:(WCServiceType)service
token:(NSString *)token
payLoad:(id)payload
usingBlock:(void (^) (NSError *error))block
{
[self addStartingServiceStatusForService:service];
[[WCWebService sharedWebService]
postStartServiceWithTarget:self
service:service
payLoad:payload
token:token
vehicle:_vehicle
usingBlock:^(id target, NSError *error, WCServiceStatus *serviceStatus) {
if (!error) {
WCServiceStatus *startingServiceStatus = [self serviceStatusForService:service];
NSManagedObjectContext *moc = _vehicle.managedObjectContext;
[moc performBlockAndWait:^{
startingServiceStatus.sentPayload = payload;
[startingServiceStatus updateWithServiceStatus:serviceStatus];
}];
block(nil);
}
else {
if (error.localizedDescription && [error.localizedDescription isEqualToString:@"Service is already started"]) {
[self serviceIsAlreadyStartedForServiceType:service block:^(NSError *error) {
if (error) {
[self failStartingServiceStatusForServiceType:service error:error serviceAlreadyStarted:YES];
}
block(error);
}];
}
else {
[self failStartingServiceStatusForServiceType:service error:error serviceAlreadyStarted:NO];
block(error);
}
}
}];
}
我首先认为错误与自我有关。但是测试存储自己也不起作用:
__weak CAPServiceManager *weakSelf = self;
也没用。我还尝试__block
作为修饰语。
如您所见,传递块。然后将它们存储在WCWebServiceRequest.m中的实例变量中,如下所示:
_block = [block copy];
... _block
定义为
@interface WCWebServiceRequest : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
@protected
id _block;
//...
...后来用这段代码调用了:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSOperationQueue *queue = [NSOperationQueue new];
queue.name = [NSString stringWithFormat:@"%s Queue", __PRETTY_FUNCTION__];
[queue addOperationWithBlock:^{
NSError *error = nil;
NSDictionary *attributes;
__block WCServiceStatus *serviceStatus;
if (_data) {
attributes = [NSJSONSerialization JSONObjectWithData:_data options:0 error:&error];
}
if (self.response.statusCode == kWCHTTPStatusCodeAccepted || self.response.statusCode == kWCHTTPStatusCodeOK) {
if ([attributes isKindOfClass:[NSDictionary class]]) {
NSManagedObjectContext *moc = [WCStorage sharedStorage].moc;
[moc performBlockAndWait:^{
serviceStatus = [WCServiceStatus makeServiceStatusWithAttributes:attributes moc:moc];
}];
}
else {
error = [NSError errorWithWebServiceErrorCode:kWCHTTPStatusCodeInvalidData];
}
}
else {
error = [NSError errorWithWebServiceErrorCode:self.response.statusCode errorInfo:[NSError errorInfoFromData:_data]];
}
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
if (!_cancelled) {
WCWebServiceServiceStatusBlock_Invoke(_block, _target, error, serviceStatus);
}
[super connectionDidFinishLoading:connection];
}];
}];
}
...其中WCWebServiceServiceStatusBlock_Invoke定义为
#define WCWebServiceServiceStatusBlock_Invoke(block, target, error, serviceStatus) \
{ \
WCWebServiceServiceStatusBlock block_ = (WCWebServiceServiceStatusBlock) block; \
block_(target, error, serviceStatus); \
}
typedef void (^WCWebServiceServiceStatusBlock) (id target, NSError *error, WCServiceStatus *serviceStatus);
...和_block如此解除分配:
- (void)dealloc
{
if (_block) {
_block = nil;
}
}
知道可能出现什么问题或如何进一步调试?
编辑:我正在使用ARC,我无法回答为什么以这种方式实现,我接管了现有的项目。
答案 0 :(得分:2)
此问题与许多问题有关。以下是我最终解决问题的步骤:
相关新代码:
- (void)userDidSignOut
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[WCWebService sharedWebService] signOut];
[_weatherRefresher stop];
[_TARefreshTimer invalidate];
[CAPSVTMessageView hide];
[[WCStorage sharedStorage].validV enumerateObjectsUsingBlock:^(WCV *obj, NSUInteger idx, BOOL *stop) {
[self unregisterFromPushNotificationsForVehicle:obj];
[obj.VHSRefresher kill];
[obj.serviceManager kill];
}];
NSOperationQueue *queue = [NSOperationQueue new];
queue.name = [NSString stringWithFormat:@"%s Queue", __PRETTY_FUNCTION__];
[queue addOperationWithBlock:^{
[[WCStorage sharedStorage] clearDatabase];
[WCStorage sharedStorage].sessionPassword = nil;
_signInFromBackround = NO;
}];
}];
}