我如何 return 一个块中的值?
How can I return a value from a block?
我很谦虚地承认我对块一无所知。
我正在编写一个 GUI 卸载程序应用程序,它使用特权帮助工具删除我产品的所有文件和目录。
因为助手是单个文件,所以我通过创建一个 TEXT 段然后将 Info.plist 复制到其中来将其 Info.plist 嵌入到可执行文件中。
到目前为止,我可以成功地使用 SMJobBless()
在 /Library/PrivilegedHelperTools
中安装该辅助工具,并在 /Library/LaunchDaemons
中安装它的 属性 列表。
Apple 建议使用 XPC 以确保 GUI 应用程序和工具具有二进制兼容版本。 EvenBetterAuthorizationSample 使用一个块调用辅助工具。我需要我的 getVersion 函数将 NSMutableString
传回给 verifyVersionCompatibility
.
- (uint32_t)getVersion: (NSMutableString**) helperVersionPtr
// Called when the user clicks the Get Version button.
// This is the simplest form of
// NSXPCConnection request because it doesn't require any authorization.
{
assert( helperVersionPtr != NULL );
assert( *helperVersionPtr != NULL );
[self connectAndExecuteCommandBlock:^(NSError * connectError) {
if (connectError != nil) {
[self logError:connectError];
*helperVersionPtr = NULL;
DBG_MSG(( "%s connectAndExecuteCommandBlock failed connectError: %s\n", __func__, [[connectError description] UTF8String] ));
} else {
[[self.helperToolConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError) {
[self logError:proxyError];
}] getVersionWithReply:^(NSString *version) {
[self logWithFormat:@"version = %@\n", version];
[*helperVersionPtr setString: version]; // Pass the version back
}];
}
}];
return 0;
}
块在这里执行:
- (void)connectAndExecuteCommandBlock:(void(^)(NSError *))commandBlock
// Connects to the helper tool and then executes
// the supplied command block on the
// main thread, passing it an error indicating
// if the connection was successful.
{
assert([NSThread isMainThread]);
// Ensure that there's a helper tool connection in place.
[self connectToHelperTool];
// Run the command block.
// Note that we never error in this case because, if there is
// an error connecting to the helper tool, it will be delivered
// to the error handler
// passed to -remoteObjectProxyWithErrorHandler:.
// However, I maintain the possibility
// of an error here to allow for future expansion.
commandBlock(nil);
}
辅助工具的getVersionWithReply:
- (void)getVersionWithReply:(void(^)(NSString * version))reply
// Part of the HelperToolProtocol.
// Returns the version number of the tool. Note that never
// requires authorization.
{
// We specifically don't check for authorization here.
// Everyone is always allowed to get
// the version of the helper tool.
reply([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]);
}
我认为你问的是如何-getVersion:
同步获取通过XPC回复获取的字符串值函数并return它给调用者。
问题是所有 XPC messages/handlers 在随机线程上异步执行。
如果你真的必须有一个同步调用,你可以使用信号量阻塞直到收到回复:
- (NSString*)synchronousExample
{
NSConditionLock* barrierLock = [[NSConditionLock alloc] initWithCondition:NO];
id<YourXPCServiceMessaging> proxy = self.serviceProxy; // get the proxy object of the XPC connection
// Send the XPC message that requests a response
__block NSString* replyString = nil;
[proxy someMessageWithStringReply:^(NSString* string){
// The XPC service has responded with the value; squirrel it away and let the original thread know it's done
replyString = string;
[barrierLock lock];
[barrierLock unlockWithCondition:YES];
}];
// Wait for the reply block to execute
[barrierLock lockWhenCondition:YES];
[barrierLock unlock];
return replyString;
}
一个更简单的方法,如果你可以重新组织你的代码,是发出一个异步请求,然后在收到回复后继续:
- (void)startVerifyCheck
{
id<YourXPCServiceMessaging> proxy = self.serviceProxy; // get the proxy object of the XPC connection
[proxy someMessageWithStringReply:^(NSString* string){
// The XPC service has responded with the value
if ([string isEqualToString:@"the expected value"])
{
// Verify successful: continue with the next step
dispatch_async(dispatch_get_main_queue(), ^{
[self verifyComplete];
});
}
}];
// Reply block will continue once the reply is received
}
- (void)verifyComplete
{
// do the next step here...
}
我很谦虚地承认我对块一无所知。
我正在编写一个 GUI 卸载程序应用程序,它使用特权帮助工具删除我产品的所有文件和目录。
因为助手是单个文件,所以我通过创建一个 TEXT 段然后将 Info.plist 复制到其中来将其 Info.plist 嵌入到可执行文件中。
到目前为止,我可以成功地使用 SMJobBless()
在 /Library/PrivilegedHelperTools
中安装该辅助工具,并在 /Library/LaunchDaemons
中安装它的 属性 列表。
Apple 建议使用 XPC 以确保 GUI 应用程序和工具具有二进制兼容版本。 EvenBetterAuthorizationSample 使用一个块调用辅助工具。我需要我的 getVersion 函数将 NSMutableString
传回给 verifyVersionCompatibility
.
- (uint32_t)getVersion: (NSMutableString**) helperVersionPtr
// Called when the user clicks the Get Version button.
// This is the simplest form of
// NSXPCConnection request because it doesn't require any authorization.
{
assert( helperVersionPtr != NULL );
assert( *helperVersionPtr != NULL );
[self connectAndExecuteCommandBlock:^(NSError * connectError) {
if (connectError != nil) {
[self logError:connectError];
*helperVersionPtr = NULL;
DBG_MSG(( "%s connectAndExecuteCommandBlock failed connectError: %s\n", __func__, [[connectError description] UTF8String] ));
} else {
[[self.helperToolConnection remoteObjectProxyWithErrorHandler:^(NSError * proxyError) {
[self logError:proxyError];
}] getVersionWithReply:^(NSString *version) {
[self logWithFormat:@"version = %@\n", version];
[*helperVersionPtr setString: version]; // Pass the version back
}];
}
}];
return 0;
}
块在这里执行:
- (void)connectAndExecuteCommandBlock:(void(^)(NSError *))commandBlock
// Connects to the helper tool and then executes
// the supplied command block on the
// main thread, passing it an error indicating
// if the connection was successful.
{
assert([NSThread isMainThread]);
// Ensure that there's a helper tool connection in place.
[self connectToHelperTool];
// Run the command block.
// Note that we never error in this case because, if there is
// an error connecting to the helper tool, it will be delivered
// to the error handler
// passed to -remoteObjectProxyWithErrorHandler:.
// However, I maintain the possibility
// of an error here to allow for future expansion.
commandBlock(nil);
}
辅助工具的getVersionWithReply:
- (void)getVersionWithReply:(void(^)(NSString * version))reply
// Part of the HelperToolProtocol.
// Returns the version number of the tool. Note that never
// requires authorization.
{
// We specifically don't check for authorization here.
// Everyone is always allowed to get
// the version of the helper tool.
reply([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]);
}
我认为你问的是如何-getVersion:
同步获取通过XPC回复获取的字符串值函数并return它给调用者。
问题是所有 XPC messages/handlers 在随机线程上异步执行。
如果你真的必须有一个同步调用,你可以使用信号量阻塞直到收到回复:
- (NSString*)synchronousExample
{
NSConditionLock* barrierLock = [[NSConditionLock alloc] initWithCondition:NO];
id<YourXPCServiceMessaging> proxy = self.serviceProxy; // get the proxy object of the XPC connection
// Send the XPC message that requests a response
__block NSString* replyString = nil;
[proxy someMessageWithStringReply:^(NSString* string){
// The XPC service has responded with the value; squirrel it away and let the original thread know it's done
replyString = string;
[barrierLock lock];
[barrierLock unlockWithCondition:YES];
}];
// Wait for the reply block to execute
[barrierLock lockWhenCondition:YES];
[barrierLock unlock];
return replyString;
}
一个更简单的方法,如果你可以重新组织你的代码,是发出一个异步请求,然后在收到回复后继续:
- (void)startVerifyCheck
{
id<YourXPCServiceMessaging> proxy = self.serviceProxy; // get the proxy object of the XPC connection
[proxy someMessageWithStringReply:^(NSString* string){
// The XPC service has responded with the value
if ([string isEqualToString:@"the expected value"])
{
// Verify successful: continue with the next step
dispatch_async(dispatch_get_main_queue(), ^{
[self verifyComplete];
});
}
}];
// Reply block will continue once the reply is received
}
- (void)verifyComplete
{
// do the next step here...
}