Странная ошибка компиляции с AVCapture после обновления до Xcode 9/Swift 4

У меня есть обычный UIViewController, который использует AVCapturePhoto, в котором я создаю собственный контроллер захвата.

Все работало правильно, пока я не обновился до Xcode 9 и не преобразовал свой код в Swift 4, и теперь, когда я пытаюсь скомпилировать, я получаю эту ошибку компиляции:

Undefined symbols for architecture x86_64: "__T0So22AVCapturePhotoSettingsC12AVFoundation01_abC16SwiftNativeTypesACWP", referenced from: __T05Union16CameraControllerC18handleCapturePhotoyyF in CameraController.o "__T012AVFoundation39_AVCapturePhotoSettingsSwiftNativeTypesPAAE016availablePreviewc11PixelFormatG0Says6UInt32VGfg", referenced from: __T05Union16CameraControllerC18handleCapturePhotoyyF in CameraController.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit код 1 (используйте -v, чтобы увидеть вызов)

И в трее ошибок показывается это сообщение:

Группа ошибок Apple Mach-O Linker

Любая подсказка, что может быть причиной этого?

Обновленная информация

Вот экран печати Xcode 9 журнала ошибок. Надеюсь, это поможет в решении ошибки компиляции.

введите здесь описание изображения

Изменить

Просто выполняю некоторые тесты - если я прокомментирую код класса, ошибка компиляции исчезнет.

Есть ли что-то неправильное в следующей реализации class, чего мне не хватает в Swift 4??

import UIKit
import AVFoundation


class CameraController: UIViewController, AVCapturePhotoCaptureDelegate, UIViewControllerTransitioningDelegate {

    let dismissButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(#imageLiteral(resourceName: "right_arrow_shadow").withRenderingMode(.alwaysOriginal), for: .normal)
        button.addTarget(self, action: #selector(handleDismiss), for: .touchUpInside)
        return button
    }()

    let capturePhotoButton: UIButton = {
        let button = UIButton(type: .system)
        button.setImage(#imageLiteral(resourceName: "capture_photo").withRenderingMode(.alwaysOriginal), for: .normal)
        button.addTarget(self, action: #selector(handleCapturePhoto), for: .touchUpInside)
        return button
    }()

    let output = AVCapturePhotoOutput()

    override func viewDidLoad() {
        super.viewDidLoad()

        transitioningDelegate = self
        setupCaptureSession()
        setupHUD()
    }


    // hiddes the status bar
    override var prefersStatusBarHidden: Bool { return true }

    //MARK: General funcs
    fileprivate func setupCaptureSession() {
        let captureSession = AVCaptureSession()

        //1. setup inputs - camera
        let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
        do {
            let input = try AVCaptureDeviceInput(device: captureDevice!)
            if captureSession.canAddInput(input) {
                captureSession.addInput(input)
            }
        } catch let err {
            print("Could not setup camera input:", err)
        }
        //2. setup outputs
        if captureSession.canAddOutput(output) {
            captureSession.addOutput(output)
        }
        //3.setup output preview
        let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)      
        previewLayer.frame = view.frame
        view.layer.addSublayer(previewLayer)

        // starts the inputs/outputs
        captureSession.startRunning()
    }


    fileprivate func setupHUD() {
        // botão de captura
        view.addSubview(capturePhotoButton)
        capturePhotoButton.anchor(top: nil, left: nil, bottom: view.bottomAnchor, right: nil, paddingTop: 0, paddinfLeft: 0, paddingBottom: 24, paddingRight: 0, width: 80, height: 80)
        capturePhotoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        // dismiss button
        view.addSubview(dismissButton)
        dismissButton.anchor(top: view.topAnchor, left: nil, bottom: nil, right: view.rightAnchor, paddingTop: 12, paddinfLeft: 0, paddingBottom: 0, paddingRight: 12, width: 50, height: 50)
    }


    @objc func handleCapturePhoto() {
        // processes the captured photo
        let settings = AVCapturePhotoSettings()
        guard let preview = settings.availablePreviewPhotoPixelFormatTypes.first else { return }
        settings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: preview]
        output.capturePhoto(with: settings, delegate: self)
    }


    @objc func handleDismiss() {
        dismiss(animated: true, completion: nil)
    }


    // Camera delegate
    func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer: CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
        // access the captured image
        let imageData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer!, previewPhotoSampleBuffer: previewPhotoSampleBuffer!)
        let previewImage = UIImage(data: imageData!)

        // shows the image
        let containerView = PreviewPhotoContainerView()
        containerView.previewImageView.image = previewImage

        view.addSubview(containerView)
        containerView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddinfLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)

    }   
}

person Ivan Cantarino    schedule 14.09.2017    source источник
comment
Ваш неопределенный символ превращается в protocol witness table for __ObjC.AVCapturePhotoSettings : AVFoundation._AVCapturePhotoSettingsSwiftNativeTypes in AVFoundation   -  person Lily Ballard    schedule 14.09.2017
comment
@KevinBallard извините, но я немного потерялся в вашем комментарии. Вы говорите, что я должен соответствовать протоколу AVCapturePhotoSettings?   -  person Ivan Cantarino    schedule 14.09.2017
comment
Я смущен, почему это дубликат другого вопроса. Эта ошибка появилась при тестировании на моем iphone7. Тот, кто пометил это как дубликат, пьян! Я нашел несколько способов решить мою проблему без использования этого кода, #if arch(x86_64)   -  person r_19    schedule 21.09.2017
comment
@ r_19 Я думаю, что Мэтт пометил это как дубликат, который является «уважаемым» пользователем iOS здесь, на SO. Дубликат, на который он указал, был просто связан с «архивом (x86_64)», возможно, он неправильно прочитал сообщение. В любом случае, мне любопытно проверить, как вы решаете эту проблему, как вы сказали.   -  person Ivan Cantarino    schedule 21.09.2017
comment
Один из способов — добавить 2 _ (символа подчеркивания) ранее к некоторым классам AVFoundation, которые Apple случайно сделала закрытыми. Например, измените settings.availablePreviewPhotoPixelFormatTypes.first else на settings.__availablePreviewPhotoPixelFormatTypes.first else. Источник: forums.developer.apple.com/thread/86810#259270   -  person r_19    schedule 26.09.2017
comment
Правильный дубликат этой ошибки - это stackoverflow.com/questions/45668293/   -  person r_19    schedule 26.09.2017
comment
да, я читал заявление Apple о том, что они по ошибке сделали некоторые функции API закрытыми. Вероятно, они скоро исправят это со следующим обновлением Xcode: D, спасибо, что указали на это.   -  person Ivan Cantarino    schedule 26.09.2017


Ответы (1)


Так что мне удалось решить эту проблему.

Каким-то образом с Xcode 9 вы не можете реализовать «бесплатный» код, который не будет работать на симуляторе iOS.

Ошибка - после ее устранения - была довольно простой.

Я не могу использовать камеру в симуляторе, потому что она не будет работать.

Я думаю, что Xcode мог бы дать более полезную информацию об ошибках.

Чтобы решить эту проблему, в моем CameraController class мне пришлось отредактировать мою функцию handleCapturePhoto().

Я должен проверить, что если бы используемая архитектура не была x86_64 (симулятор), то я мог бы представить вывод камеры.

Это состояние решения функции:

@objc func handleCapturePhoto() {
    // processes the captured photo
    let settings = AVCapturePhotoSettings()

    // doesn't show in the simulator
    #if (!arch(x86_64))
        guard let preview = settings.previewPhotoFormat?.first else { return }
        settings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: preview]
        output.capturePhoto(with: settings, delegate: self)
    #endif
}

Надеюсь, это поможет кому-то в будущем.

person Ivan Cantarino    schedule 14.09.2017
comment
Это позволит вам построить и запустить свой проект, но не является истинным решением проблемы. Я попробовал это и заменил другие решения, которые я нашел, не используя #if (!arch(x86_64)), и это не вело себя так, как ожидалось. Но, если это работает для вас, это работает для вас. Просто имейте в виду, что это решение может решить эту проблему, но заменить ее новой проблемой. - person r_19; 21.09.2017
comment
Это довольно просто. Если устройство является симулятором - не открывайте камеру. Это просто для тестирования, в релизной версии я все равно могу удалить #ifdef, если захочу - person Ivan Cantarino; 21.09.2017
comment
Как я уже упоминал, я попробовал это решение на своем iphone 7, и оно ДЕЙСТВИТЕЛЬНО удалило ошибку компиляции, но оно НЕ вело себя так, как ожидалось. Итак, просто убедитесь, что все ваши функции работают должным образом. Если да, то ты молодец. - person r_19; 26.09.2017
comment
@ r_19 ооо ... тогда это сработало. Я неверно истолковал то, что вы сказали. Извини - person Ivan Cantarino; 26.09.2017
comment
На самом деле это известная ошибка в xcode 9, официальный ответ Apple - использовать версии этого API SwiftPrivate, добавляя перед каждым API двойное подчеркивание (__). Например, измените AVCaptureDevice.Format.supportedColorSpaces на AVCaptureDevice.Format.__supportedColorSpaces. - person Christopher Larsen; 26.09.2017
comment
@ChristopherLarsen да, я знаю (сейчас); Я надеюсь, что они исправят это со следующим обновлением Xcode, потому что это довольно раздражает. - person Ivan Cantarino; 26.09.2017
comment
@ChristopherLarsen создаст ли это проблему, когда мы отправляем приложение на проверку? - person vishal dharankar; 03.10.2017
comment
@vishaldharankar, вероятно, нет, по крайней мере, я надеюсь, что нет, но в релизной версии вы можете удалить #ifdef, поскольку он предназначен только для симуляторов. Я, вероятно, уберу эту проверку в релизной версии и добавлю ее только для целей разработки. - person Ivan Cantarino; 03.10.2017
comment
@IvanCantarino спрашивает об этих строках от AVCaptureDevice.Format.supportedColorSpaces до AVCaptureDevice.Format.__supportedColorSpaces. - person vishal dharankar; 03.10.2017
comment
@vishaldharankar о, извините, я думал, что вы касаетесь самой темы. Виноват - person Ivan Cantarino; 03.10.2017
comment
@vishaldharankar Не следует, решение пришло от Apple. Я реализовал это в коде, который уже прошел проверку. forums.developer.apple.com/thread/86810 - person Christopher Larsen; 03.10.2017