'Any' 无法转换为 'AVCaptureDevice' 将 Objective C 转换为 Swift 时出错

'Any' is not convertible to 'AVCaptureDevice' error translating Objective C to Swift

我正在重建 Google Mobile Vision "Googly Eyes" demo Swift 3. 我几乎想通了,但我一直在翻译从 Objective C 到 Swift 的函数。

演示视图控制器中的Objective C函数是:

  - (AVCaptureDeviceInput *)cameraForPosition:(AVCaptureDevicePosition)desiredPosition {
    BOOL hadError = NO;
    for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) {
      if ([device position] == desiredPosition) {
        NSError *error = nil;
        AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
                                                                            error:&error];
        if (error) {
          hadError = YES;
          NSLog(@"Could not initialize for AVMediaTypeVideo for device %@", device);
        } else if ([self.session canAddInput:input]) {
          return input;
        }
      }
    }
    if (!hadError) {
      NSLog(@"No camera found for requested orientation");
    }
    return nil;
  }

我已将其翻译成以下内容:

func camera(for desiredPosition: AVCaptureDevicePosition) -> AVCaptureDeviceInput {
    var hadError: Bool = false
    for device: AVCaptureDevice in AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) { // ERROR ON THIS LINE
        if device.position() == desiredPosition {
            var error: Error? = nil
            let input = try? AVCaptureDeviceInput(device: device)
            if error != nil {
                hadError = true
                print("Could not initialize for AVMediaTypeVideo for device \(device)")
            }
            else if session.canAdd(input!) {
                return input!
            }
        }
    }
    if !hadError {
        print("No camera found for requested orientation")
    }
  }

我遇到的错误在第 3 行 (for device: AVCaptureDevice in AVCaptureDevice.devices...)。错误是:'Any' is not convertible to 'AVCaptureDevice'。我对 Objective C 不是很熟悉并且之前从未使用过 AVCaptureSession 所以我一直在努力弄清楚它。关于我需要如何重写此 "for device" 语句的任何建议?

假设您使用 Xcode 的最新发布版本。在 post.

时是 Xcode 8.3.3

我给你看一些简化案例的代码。


案例一

继续使用已弃用的方法(不推荐):

func camera(for desiredPosition: AVCaptureDevicePosition) -> AVCaptureDeviceInput? {
    var hadError: Bool = false
    for device in AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as! [AVCaptureDevice] { //### You need to cast
        if device.position == desiredPosition {
            do {
                let input = try AVCaptureDeviceInput(device: device)
                if session.canAddInput(input) { //###<-
                    return input
                }
            } catch {
                hadError = true
                print("Could not initialize for AVMediaTypeVideo for device \(device) with \(error)")
            }
        }
    }
    if !hadError {
        print("No camera found for requested orientation")
    }
    return nil
}

devices(withMediaType:)的return类型是[Any]!,所以如果想把每个元素都当成AVCaptureDevice,就需要强制转换

与您的代码类似,但我修复了一些部分,canAddcanAddInput 和错误处理。


案例二

使用 AVCaptureDeviceDiscoverySession 忽略比 10.0 更旧的 iOS 版本。

func camera(for desiredPosition: AVCaptureDevicePosition) -> AVCaptureDeviceInput? {
    var hadError: Bool = false
    for device in AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: desiredPosition).devices {
        do {
            let input = try AVCaptureDeviceInput(device: device)
            if session.canAddInput(input) {
                return input
            }
        } catch {
            hadError = true
            print("Could not initialize for AVMediaTypeVideo for device \(device) with \(error)")
        }
    }
    if !hadError {
        print("No camera found for requested orientation")
    }
    return nil
}

使用AVCaptureDeviceDiscoverySession的简单示例,.builtInWideAngleCamera在双摄像头设备上匹配前置摄像头、普通后置摄像头和广角摄像头。


注意

上述代码中的很多方法在Swift4/Xcode9中改变了它们的签名,包括return类型。在 iOS SDK 11 中,有一个很好的方法:

class func default(AVCaptureDevice.DeviceType, for: AVMediaType?, position: AVCaptureDevice.Position)