Objective c 为什么在dispatch\u async(dispatch\u get\u main\u queue()之后的块从未被调用?

Objective c 为什么在dispatch\u async(dispatch\u get\u main\u queue()之后的块从未被调用?,objective-c,xcode,macos,grand-central-dispatch,dispatch-async,Objective C,Xcode,Macos,Grand Central Dispatch,Dispatch Async,我想异步执行一些代码,并因此开始使用GCD for OSX/iOS。 目前我正在使用函数dispatch_async()。 当我想在另一个线程上并发执行某个任务时,我使用函数dispatch\u get\u global\u queue()。 当我想将结果分派到主线程时,我使用函数dispatch_get_main_queue()。 但结果永远不会到达主线 在调试器中设置断点时(在dispatch\u async行),函数dispatch\u async之后的块(dispatch\u get\u

我想异步执行一些代码,并因此开始使用GCD for OSX/iOS。
目前我正在使用函数dispatch_async()。
当我想在另一个线程上并发执行某个任务时,我使用函数dispatch\u get\u global\u queue()。
当我想将结果分派到主线程时,我使用函数dispatch_get_main_queue()。
但结果永远不会到达主线

在调试器中设置断点时(在dispatch\u async行),函数dispatch\u async之后的块(dispatch\u get\u global\u queue(dispatch\u queue\u PRIORITY\u DEFAULT,0) 只在某些时候执行,但调试器通常会忽略它。
当执行块并且执行流到达dispatch_async(dispatch_get_main_queue())的断点时,之后的块总是被忽略

如果没有dispatch_async(dispatch_get_global_queue)和dispatch_async(dispatch_get_main_queue),代码将按其应该的方式执行,尽管是同步的

我的问题是,为什么在dispatch\u async(dispatch\u get\u global\u queue()块中的dispatch\u async(dispatch\u get\u main\u queue()永远不会执行?
同样,为什么每次都不执行dispatch\u async(dispatch\u get\u global\u queue()块

我的开发环境是
OS:OS X 10.11.3
IDE:Xcode 7.2
编译器:苹果LLVM 7.0.2版(clang-700.1.81)
目标:x86_64-apple-darwin15.3.0

下面是一个简单的示例,它再现了不稳定的行为(一个OS X控制台应用程序):

TestClass.h

TestClass.m

#导入
#导入“TestClass.h”
@实现测试类
-(void)testMethod:(NSString*)带completionBlock的testString:(void(^)(NSString*blockResult,NSError\uu autoreleasing*error))completionBlock{
__块NSString*stringResult=nil;
if(完成块){
__块N错误*结果错误=零;
调度异步(调度获取全局队列(调度队列优先级默认为0)^{
//此块仅在某些时候被调用,大多数情况下被忽略。
如果([testString isEqual:@“错误字符串”]){
NSDictionary*errorUserInfo=@{NSLocalizedDescriptionKey:@“这是一个错误”,NSLocalizedFailureReasonErrorKey:@“”,NSLocalizedRecoverysSuggestionErrorKey:@“”;
resultError=[[NSError alloc]initWithDomain:@“com.test.TestErrorDomain”代码:10 userInfo:errorUserInfo];
}
否则{
stringResult=testString;
}
dispatch\u async(dispatch\u get\u main\u queue()^{
//这个块永远不会被执行。
completionBlock(stringResult、resultError);
});
});
}
}
@结束
main.m

#import <Foundation/Foundation.h>
#import "TestClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"BEFORE BLOCK");

        __block NSString *resultString = nil;
        TestClass * testObject = [[TestClass alloc] init];
        dispatch_semaphore_t sem = dispatch_semaphore_create(0);

        [testObject testMethod:@"Test string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE FIRST BLOCK");

             resultString = blockString;

             if (resultString)
             {
                 NSLog(@"The result string is: %@.", resultString);
             }
         }];

        [testObject testMethod:@"Error string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE SECOND BLOCK");

             resultString = blockString;

             if (!resultString)
             {
                 if (error)
                 {
                     NSLog(@"Error: %@", [error localizedDescription]);
                 }
                 else
                 {
                     NSLog(@"Error not recognized!");
                 }
             }
         }];

        NSLog(@"AFTER BLOCK!");

        while (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW))
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    }

    return 0;
}
#导入
#导入“TestClass.h”
int main(int argc,const char*argv[]{
@自动释放池{
__块NSString*resultString=nil;
TestClass*testObject=[[TestClass alloc]init];
//此调用的输出应为:结果字符串为:测试字符串。
[testObject testMethod:@“Test string”with CompletionBlock:^(NSString*blockString,NSError\uU autoreleasing*错误){
结果字符串=块字符串;
如果(结果字符串){
NSLog(@“结果字符串为:%@.”,resultString);
}
}];
//此调用的输出应为:Error:这是一个错误。
[testObject testMethod:@“Error string”with completionblock:^(NSString*blockString,NSError\uu autoreleasing*Error){
结果字符串=块字符串;
如果(!resultString){
如果(错误){
NSLog(@“错误:%@,[Error localizedDescription]);
}
否则{
NSLog(@“无法识别错误!”);
}
}
}];
}
返回0;
}

这是因为一旦main()函数退出,TestClass对象就会被释放。testMethod:主要是异步的,它不会阻止main()中的指针


尝试在main()的末尾添加一个信号量。这个信号量应该在testMethod
dispatch\u async(dispatch\u get\u main\u queue(),^{})中发出信号。
块。

下面是一个使用信号量的工作示例,如@charleshierry的回答所示。 我还包括了一些帮助说明执行流程的NSlog:

TestClass.h

TestClass.m

#导入
#导入“TestClass.h”
@实现测试类
-(void)testMethod:(NSString*)带信号量的testString:(dispatch_信号量_t)带completionBlock的sem:(void(^)(NSString*blockResult,NSError\u autoreleasing*error))completionBlock{
__块NSString*stringResult=nil;
if(完成块){
__块N错误*结果错误=零;
NSLog(@“内部测试方法,外部调度异步”);
调度异步(调度获取全局队列(调度队列优先级默认为0)^{
NSLog(@“在调度异步到全局队列中”);
如果([testString isEqual:@“错误字符串”]){
NSDictionary*errorUserInfo=@{NSLocalizedDescriptionKey:@“这是一个错误”,NSLocalizedFailureReasonErrorKey:@“”,NSLocalizedRecoverysSuggestionErrorKey:@“”;
resultError=[[NSError alloc]initWithDomain:@“com.test.TestErrorDomain”代码:10 userInfo:errorUserInfo];
}
否则{
stringResult=testString;
}
dispatch\u async(dispatch\u get\u main\u queue()^{
NSLog(@“调度内部异步到主队列!”);
completionBlock(stringResult、resultError);
调度信号量信号(sem);
});
});
}
}
@结束
main.m

#import <Foundation/Foundation.h>
#import "TestClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"BEFORE BLOCK");

        __block NSString *resultString = nil;
        TestClass * testObject = [[TestClass alloc] init];
        dispatch_semaphore_t sem = dispatch_semaphore_create(0);

        [testObject testMethod:@"Test string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE FIRST BLOCK");

             resultString = blockString;

             if (resultString)
             {
                 NSLog(@"The result string is: %@.", resultString);
             }
         }];

        [testObject testMethod:@"Error string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE SECOND BLOCK");

             resultString = blockString;

             if (!resultString)
             {
                 if (error)
                 {
                     NSLog(@"Error: %@", [error localizedDescription]);
                 }
                 else
                 {
                     NSLog(@"Error not recognized!");
                 }
             }
         }];

        NSLog(@"AFTER BLOCK!");

        while (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW))
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    }

    return 0;
}
#导入
#导入“TestClass.h”
int main(int argc,const char*argv[]{
@aut
#import <Foundation/Foundation.h>
#import "TestClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        __block NSString *resultString = nil;
        TestClass * testObject = [[TestClass alloc] init];

        // Output for this call should be: The result string is: Test string.
        [testObject testMethod:@"Test string" withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error) {
            resultString = blockString;

            if (resultString) {
                NSLog(@"The result string is: %@.", resultString);
            }
        }];

        // Output for this call should be: Error: This is an error.
        [testObject testMethod:@"Error string" withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error) {
            resultString = blockString;

            if (!resultString) {
                if (error) {
                    NSLog(@"Error: %@", [error localizedDescription]);
                }
                else {
                    NSLog(@"Error not recognized!");
                }
            }
        }];
    }

    return 0;
}
#ifndef TestClass_h
#define TestClass_h

@interface TestClass : NSObject {
}

- (void)testMethod:(NSString *)testString withSemaphore:(dispatch_semaphore_t)sem withCompletionBlock:(void(^)(NSString *blockResult, NSError __autoreleasing *error))completionBlock;

@end

#endif
#import <Foundation/Foundation.h>
#import "TestClass.h"

@implementation TestClass

- (void)testMethod:(NSString *)testString withSemaphore:(dispatch_semaphore_t)sem withCompletionBlock:(void(^)(NSString *blockResult, NSError __autoreleasing *error))completionBlock {
    __block NSString *stringResult = nil;

    if (completionBlock) {
        __block NSError *resultError = nil;

        NSLog(@"INSIDE TEST METHOD, OUTSIDE DISPATCH ASYNC");

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            NSLog(@"INSIDE THE DISPATCH ASYNC TO THE GLOBAL QUEUE");

            if ([testString isEqual: @"Error string"]) {
                NSDictionary *errorUserInfo = @{ NSLocalizedDescriptionKey: @"This is an error.", NSLocalizedFailureReasonErrorKey: @"", NSLocalizedRecoverySuggestionErrorKey: @"" };
                resultError = [[NSError alloc] initWithDomain:@"com.test.TestErrorDomain" code:10 userInfo:errorUserInfo];
            }
            else {
                stringResult = testString;
            }

            dispatch_async(dispatch_get_main_queue(), ^{
                NSLog(@"INSIDE THE DISPATCH ASYNC TO THE MAIN QUEUE!");
                completionBlock(stringResult, resultError);
                dispatch_semaphore_signal(sem);
            });
        });
    }
}

@end
#import <Foundation/Foundation.h>
#import "TestClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSLog(@"BEFORE BLOCK");

        __block NSString *resultString = nil;
        TestClass * testObject = [[TestClass alloc] init];
        dispatch_semaphore_t sem = dispatch_semaphore_create(0);

        [testObject testMethod:@"Test string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE FIRST BLOCK");

             resultString = blockString;

             if (resultString)
             {
                 NSLog(@"The result string is: %@.", resultString);
             }
         }];

        [testObject testMethod:@"Error string" withSemaphore:sem withCompletionBlock:^(NSString *blockString, NSError __autoreleasing *error)
         {
             NSLog(@"INSIDE SECOND BLOCK");

             resultString = blockString;

             if (!resultString)
             {
                 if (error)
                 {
                     NSLog(@"Error: %@", [error localizedDescription]);
                 }
                 else
                 {
                     NSLog(@"Error not recognized!");
                 }
             }
         }];

        NSLog(@"AFTER BLOCK!");

        while (dispatch_semaphore_wait(sem, DISPATCH_TIME_NOW))
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    }

    return 0;
}