You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xcode 11.3.1真机编译报错:未声明类型‘PHAccessLevel’及‘PHPhotoLibrary’无‘presentLimitedLibraryPicker’成员

Fixing "Undeclared type 'PHAccessLevel'" and "No member 'presentLimitedLibraryPicker'" on Real Devices with Xcode 11.3.1

Hey there! Let's break down why you're hitting these frustrating errors only on real devices, even though your code works in the simulator and you've tried common fixes like cleaning builds.

The Root Cause

The issue comes down to a SDK version mismatch. Xcode 11.3.1 ships with the iOS 13.2 SDK, which doesn't include the PHAccessLevel type or PHPhotoLibrary.presentLimitedLibraryPicker(from:) method—these are both iOS 14+ exclusive APIs.

Even though you're testing on iOS 14/13 devices, when you compile with Xcode 11.3.1, the compiler uses the older iOS 13.2 SDK to validate your code. The simulator might seem to work because it's tied directly to your Xcode version's SDK, but real devices expose the gap between the SDK you're compiling with and the runtime APIs they support. Your previous fixes (cleaning builds, deleting Derived Data) don't help here because the problem isn't cached artifacts—it's missing API definitions in the SDK.

Solutions

1. Upgrade Xcode (Recommended)

The simplest and most reliable fix is to upgrade Xcode to version 12.0 or later. Xcode 12 was the first release to include the iOS 14 SDK, which has all the Photos framework APIs you're using. Once you upgrade, your existing code will compile and run on iOS 14+ real devices without any changes.

2. Workaround for Xcode 11.3.1 (If You Can't Upgrade)

If you're stuck on Xcode 11.3.1 for now, you can use runtime checks and dynamic method calls to avoid compilation errors. This lets you access the iOS 14 APIs without the compiler flagging them as missing. Here's how to modify your code:

import Photos
import PhotosUI
import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if #available(iOS 14, *) {
            // Dynamically fetch PHAccessLevel.readWrite since it's not in iOS 13 SDK
            guard let phAccessLevelClass = NSClassFromString("PHAccessLevel"),
                  let readWriteAccessLevel = phAccessLevelClass.value(forKey: "readWrite") as? NSNumber else {
                // Fall back to iOS 13 authorization flow if dynamic access fails
                handleLegacyAuthorization(PHPhotoLibrary.authorizationStatus())
                return
            }
            
            // Call authorizationStatus(for:) dynamically
            let authorizationStatusRaw = PHPhotoLibrary.shared()
                .perform(Selector(("authorizationStatusForAccessLevel:")), with: readWriteAccessLevel)?
                .takeUnretainedValue() as? Int ?? 0
            
            switch authorizationStatusRaw {
            case 3: // Raw value for PHAuthorizationStatus.limited
                // Call presentLimitedLibraryPicker(from:) dynamically
                PHPhotoLibrary.shared()
                    .perform(Selector(("presentLimitedLibraryPickerFromViewController:")), with: self)
            case 4: // Raw value for PHAuthorizationStatus.authorized
                handleAuthorizedAccess()
            default:
                handleUnauthorizedAccess()
            }
        } else {
            // iOS 13 and below authorization flow
            handleLegacyAuthorization(PHPhotoLibrary.authorizationStatus())
        }
    }
    
    // MARK: - Helper Methods
    private func handleLegacyAuthorization(_ status: PHAuthorizationStatus) {
        switch status {
        case .authorized:
            handleAuthorizedAccess()
        default:
            handleUnauthorizedAccess()
        }
    }
    
    private func handleAuthorizedAccess() {
        // Your logic for authorized access goes here
        print("Photo access authorized")
    }
    
    private func handleUnauthorizedAccess() {
        // Your logic for unauthorized access goes here
        print("Photo access not authorized")
    }
}

A quick breakdown of this workaround:

  • We use NSClassFromString to fetch the PHAccessLevel class dynamically, since the compiler doesn't recognize it in Xcode 11.3.1.
  • We call the new authorization methods with performSelector to bypass compiler checks.
  • We use raw values for authorization statuses because PHAuthorizationStatus.limited isn't defined in the iOS 13 SDK.

内容的提问来源于stack exchange,提问作者Heshan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 10:57:49