开发者

dyld: Symbol not found problem (NSMutableAttributedString seems to be strongly linked)

[edited] I edited the question to isolate the problem and help other people better.


I'm using NSMutableAttributedString class in my app, which is available in iOS 3.2 and later. I'm also targeting 3.1.2-version devices though; for the backward compatibility, I used the following code:

CFAttributedStringRef attributedString;
if (NSClassFromString(@"NSMutableAttributedString")) {
    attributedString = (CFAttributedStringRef)[[[NSMutableAttributedString alloc] 
            /* init... to initialize an object */ ] autorelease];
} else {
    attributedString = CFAttributedStringCreate(kCFAllocatorDefault,
            (CFStringRef)NSLocalizedString(@"MessageInEllipse",
            @"Message to show in an ellipse"),
            (CFDictionaryRef)attributes);
    }
}

In line 3, I directly use the class name NSMutableAttributedString, but I expected this to be weakly linked by the linker, so it mer开发者_如何转开发ely means nil here and the app would work without problems.

However, my app crashes on 3.1.2 devices when it launches, complaining that it can't find symbol NSMutableAttributedString. It seems like this class symbol is strongly linked. Why would this happen?


You need to change the framework linking configuration to "weak" link to the framework you are testing in the code.


Weak linking to a specific class is not available in all cases. In order to weakly link a class symbol,

  • The base SDK must be iOS 4.2 or newer.
  • The deployment target must be iOS 3.1 or newer.
  • The compiler must be the LLVM-GCC 4.2 or newer, or LLVM-Clang 1.5 or newer.
  • The class to which you want to weakly link must be declared using NS_CLASS_AVAILABLE macro.
  • The framework that the class belongs to must exist in the version for deployment, and if otherwise the framework itself must be weakly linked.

The third condition was my problem because I wrongfully thought I was using LLVM (I only found this with a help in the Apple's forum). GCC is the Xcode 3 default, so you must be careful.

If these condition doesn't hold, you cannot use weak linking. In this case, instead of using [NSMutableAttributedString alloc], for example, I should do like [NSClassFromString(@"NSMutableAttributedString") alloc].

There's one thing left to mention. As in @sza's answer, if I weakly link against the framework itself (Foundation in this case), I can use weak linking to the missing class even with GCC 4.2. Although it can solve the problem right away, in my opinion, it seems like a practice that should be avoided. I'm cautious in this because I'm not sure how weak linking to a framework does work in runtime, but wouldn't it impose more performance overhead than strongly linking to a framework, because all the information about the framework need to be acquired in runtime? Therefore, if I weakly link against a framework that is frequently used (sure does Foundation), I guess I could have a performance problem. At least, the references are very specific to say weakly link against a framework if that framework is not available for some of your deployment targets.

Therefore, I think the best practice here is:

  • always strongly link against frameworks that are available in my deployment target

and if I'm using a class of the framework that becomes available after the deployment target,

  1. use weak linking if I can meet the requirements, OR
  2. always use NSClassFromString() to refer to the class, no matter it would be executed or not in the older versions of iOS.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜