Inconsistent Symbol Linking Behavior for UTType from UniformTypeIdentifiers Framework

In our app, we implement a document picker using FilePickerManager+available.m, selecting different APIs based on the iOS version:

if (@available(iOS 14.0, *)) {
    NSMutableArray<UTType *> *contentTypes = [NSMutableArray array];
    
    for (NSString *uti in documentTypes) {
        UTType *type = [UTType typeWithIdentifier:uti];
        if (type) {
            [contentTypes addObject:type];
            NSLog(@"iOS 14+ Adding type: %@", uti);
        } else {
            NSLog(@"Warning: Unable to create UTI: %@", uti);
        }
    }
    
    UIDocumentPickerViewController *documentPicker =
        [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:contentTypes];
    documentPicker.delegate = self;
    documentPicker.allowsMultipleSelection = NO;
    
    [self.presentingViewController presentViewController:documentPicker animated:YES completion:nil];
}

However, we've observed inconsistent symbol reference types to UTType in the final linked binaries:

  • One build results in a strong reference to UTType.
  • Another demo project (with seemingly identical code and build settings) results in a weak reference.

Both object files (.o) show undefined references to UTType symbols (e.g., UTTypeCreatePreferredIdentifierForTag), yet the final linked binaries differ in how these symbols are resolved.

Impact of the Issue

This inconsistency causes problems on iOS 14.0+ devices:

  • Strong reference version: Fails to launch on devices where the UniformTypeIdentifiers framework is not present (e.g., certain older iOS 14.x devices), due to link-time failure.
  • Weak reference version: Launches successfully but crashes at runtime when attempting to call UTType methods, because the implementation cannot be found.

Our Analysis

  • Using nm -u, both versions show an undefined symbol:

U _UTTypeCreatePreferredIdentifierForTag

  • However, in the final binaries:
  1. One shows: T _UTTypeCreatePreferredIdentifierForTag (strong)
  2. The other shows: W _UTTypeCreatePreferredIdentifierForTag (weak)

Both projects link against the framework identically in their build logs:

-framework UniformTypeIdentifiers (no -weak_framework flag is used in either case).

Questions

  1. Why do identical source code and linker flags result in different symbol reference strengths (T vs W) for the same framework?
  2. Are there specific compiler or linker behaviors (e.g., deployment target, SDK version, module imports, or bitcode settings) that influence whether symbols from UniformTypeIdentifiers are treated as strong or weak?
  3. What is the recommended best practice to ensure consistent symbol referencing when using newer APIs like UTType, especially when supporting older OS versions?

We aim to understand this behavior to guarantee stable operation across all supported iOS versions—avoiding both launch failures and runtime crashes caused by inconsistent symbol linking.

Any insights or guidance from the community or Apple engineers would be greatly appreciated!

Let me know if you'd like a shorter version or want to include additional build environment details (Xcode version, deployment target, etc.)!

What version of Xcode are you using here?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Inconsistent Symbol Linking Behavior for UTType from UniformTypeIdentifiers Framework
 
 
Q