简体   繁体   English

在iOS中测试弱链接符号无法正常工作

[英]Testing for weak-linked symbol in iOS does not work as expected

I am running into a weird issue when trying to test for the existence of a symbol that is introduced in a newer version of the OS. 当尝试测试在较新版本的OS中引入的符号的存在时,我遇到一个奇怪的问题。 I follow the Apple guidelines on using weak-linked symbols, ie 我遵循Apple准则使用弱链接符号,即

Check the availability of an external (extern) constant or a notification name by explicitly comparing its address—and not the symbol's bare name—to NULL or nil. 通过将地址(而不是符号的裸名)与NULL或nil进行显式比较,来检查外部(外部)常量或通知名称的可用性。

To reproduce the issue, I am using the latest iOS 6 SDK on the latest Xcode 4.5.2, using the default compiler (Apple LLVM compiler 4.1). 为了重现此问题,我使用默认的编译器(Apple LLVM编译器4.1)在最新的Xcode 4.5.2上使用最新的iOS 6 SDK。 I weak-linked the Social framework (which is only available on iOS 6+). 我弱链接了社交框架(仅在iOS 6+上可用)。 And I run this code on iOS 5.1 (the deployment target is lower than 6): 然后在iOS 5.1上运行以下代码(部署目标低于6):

NSLog(@"%p", &SLServiceTypeFacebook);
if (&SLServiceTypeFacebook)
  NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
  NSLog(@"Yes2");

The output is: 输出为:

0x0
Yes1
Yes2

In other words, we can verify at runtime that the expression &SLServiceTypeFacebook evaluates to the value 0. Yet, if statements that test on this expression treat it as if it is true. 换句话说,我们可以在运行时验证表达式&SLServiceTypeFacebook的值为0。但是, if对此表达式进行测试的语句将其视为真。


Update: From this question , I found that this workaround works with no optimization, but not with optimization: 更新:这个问题开始 ,我发现此解决方法没有优化,但是没有优化:

typeof(&SLServiceTypeFacebook) foo = &SLServiceTypeFacebook;
if (foo)
  NSLog(@"Yes3"); // does not get executed on -O0, but does on any optimization

Update: It appears that this problem does not exist with UIKit symbols. 更新:看来UIKit符号不存在此问题。 Running the following on iOS 4.3: 在iOS 4.3上运行以下命令:

NSLog(@"%p", &UIKeyboardDidChangeFrameNotification);
if (&SLServiceTypeFacebook)
  NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
  NSLog(@"Yes2");

The output is: 输出为:

0x0

I hypothesize that the difference is that the UIKit symbol has a NS_AVAILABLE_IOS() macro next to it, so somehow the compiler handles it correctly. 我假设不同之处在于,UIKit符号旁边有一个NS_AVAILABLE_IOS()宏,因此编译器会以某种方式正确处理它。 In the case of the Social framework symbol, it doesn't have a NS_AVAILABLE_IOS() macro since the entire Social framework itself is only available since iOS 6 (ie the symbol is available since the version of the framework, so I guess the don't need this macro?); 就社交框架符号而言,它没有NS_AVAILABLE_IOS()宏,因为整个社交框架本身仅自iOS 6起可用(即,该符号自框架版本开始可用,因此我猜不需要这个宏吗?); but then the compiler does not handle the symbol correctly. 但是编译器无法正确处理该符号。

Are you sure you don't want to check that the SLRequest class exists instead of checking for this constant? 您确定不想检查SLRequest类是否存在而不是检查此常量吗?

In any case, the issue is that the compiler is optimizing the test away (it interprets this as testing a constant expression which is true at compile time). 无论如何,问题在于编译器正在优化测试(将其解释为测试在编译时为真的常量表达式)。 You can circumvent this by reading this address into a local volatile variable. 您可以通过将该地址读取到本地volatile变量中来规避此问题。 Or you could dynamically search for the symbol at runtime. 或者,您可以在运行时动态搜索符号。

But I would consider just checking for the SLRequest class instead. 但是我会考虑只检查SLRequest类。

Here are at least these three options: 这里至少是这三个选项:

#include <dlfcn.h>

NSString* const * volatile check = &SLServiceTypeFacebook;
if (check != NULL)
    NSLog(@"SLServiceTypeFacebook is defined");

// Another approach would be to call dlsym() at runtime 
// to search for this symbol:
if (dlsym(RTLD_DEFAULT, "SLServiceTypeFacebook"))
    NSLog(@"SLServiceTypeFacebook found via dlsym");

// But if you really just wanted to know is if SLRequest
// is available, you should really just do this:
if ([SLRequest class])
    NSLog(@"SLRequest class is available");

Any of these should work as you were expecting in iOS5.1 versus iOS6. 这些中的任何一个都可以像您期望的那样在iOS5.1和iOS6中正常工作。

Hope that helps. 希望能有所帮助。

只需检查NSClassFromString是否可以获取这些类。objC无论如何都是所有类:D

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM