首页 > 解决方案 > 在 Swift 中编码时出现 Python 错误:意外缩进 (Xcode 11)

问题描述

编辑:对于那些想要实际代码的人,请查阅此链接以获取所有相关源代码。 https://github.com/objcio/S01E118-introduction-prototype

为什么我会收到以下错误:

错误:模块导入失败:意外缩进(sniff_objc_exception_throw.py,第 7 行)文件“temp.py”,第 1 行,在

我正在使用 SwiftTalk 的一个项目示例,它在任何地方都没有任何明显的 python 代码,这让我认为这可能是一个 Xcode 导入问题。有人见过这个吗?我能做些什么来解决这个问题吗?

在此处输入图像描述

项目代码使用旧版本的 Swift(马特在下面指出......)。这是我在更新以删除所有编译错误并运行 Convert/Update to Swift 5 Utility 后的代码:

import UIKit

extension UIView {
    func setSubviews<S: Sequence>(_ other: S) where S.Element == UIView {
        let views = Set(other)
        let sub = Set(subviews)
        for v in sub.subtracting(views) {
            v.removeFromSuperview()
        }
        for v in views.subtracting(sub) {
            addSubview(v)
        }
    }
}


extension UILabel {
    convenience init(text: String, size: UIFont.TextStyle, multiline: Bool = false) {
        self.init()
        font = UIFont.preferredFont(forTextStyle: size)
        self.text = text
        adjustsFontForContentSizeCategory = true
        if multiline {
            numberOfLines = 0
        }
    }
}

indirect enum Layout {
    case view(UIView, Layout)
    case newline(Layout)
    case choice(Layout, Layout)
    case empty
}

extension Layout {
    func apply(containerWidth: CGFloat) -> [UIView] {
        var result: [UIView] = []
        var origin: CGPoint = .zero
        var current: Layout = self
        var lineHeight: CGFloat = 0
        while true {
        switch current {
            case let .view(v, rest):
                result.append(v)
                let availableWidth = containerWidth - origin.x
                let size = v.sizeThatFits(CGSize(width: availableWidth, height: .greatestFiniteMagnitude))
                v.frame = CGRect(origin: origin, size: size)
                lineHeight = max(lineHeight, size.height)
                origin.x += size.width
                current = rest
            case let .newline(rest):
                origin.x = 0
                origin.y += lineHeight
                lineHeight = 0
                current = rest
            case let .choice(first, second):
                if first.fits(currentX: origin.x, containerWidth: containerWidth) {
                    current = first
                } else {
                    current = second
                }
            case .empty:
                return result
            }
        }
    }

    func fits(currentX: CGFloat, containerWidth: CGFloat) -> Bool {
        var x = currentX
        var current: Layout = self
        while true {
            switch current {
            case let .view(v, rest):
                let availableWidth = containerWidth - x
                let size = v.sizeThatFits(CGSize(width: availableWidth, height: .greatestFiniteMagnitude))
                x += size.width
                if x >= containerWidth { return false }
                current = rest
            case let .newline(rest):
                x = 0
                current = rest
            case let .choice(first, second):
                if first.fits(currentX: x, containerWidth: containerWidth) {
                    return true
                } else {
                    current = second
                }
            case .empty:
                return true
            }
        }
    }
}

final class LayoutContainer: UIView {
    let layout: Layout
    init(_ layout: Layout) {
        self.layout = layout
        super.init(frame: .zero)

//        NotificationCenter.default.addObserver(self, selector: #selector(setNeedsLayout), name: Notification.Name.UIContentSizeCategory.didChangeNotification, object: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func layoutSubviews() {
        let views = layout.apply(containerWidth: bounds.width)
        setSubviews(views)
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let titleLabel = UILabel(text: "Building a Layout Library", size: .headline, multiline: true)
        let episodeNumber = UILabel(text: "Episode 123", size: .body)
        let episodeDate = UILabel(text: "September 23", size: .body)

        let horizontal = Layout.view(episodeNumber, Layout.view(episodeDate, .empty))
        let vertical = Layout.view(episodeNumber, .newline(Layout.view(episodeDate, .empty)))
        let layout = Layout.view(titleLabel, .newline(
            .choice(horizontal, vertical)
            ))

        let container = LayoutContainer(layout)
        container.translatesAutoresizingMaskIntoConstraints = false

        view.addSubview(container)
        view.addConstraints([
            container.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
            container.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
            container.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
        ])

    }
}

需要明确的是:如果您将此代码复制并粘贴到项目的现有 ViewController.swift 内容上,则项目将编译,然后仅以指示的错误运行(模块导入失败:....)

标签: pythonswiftxcode

解决方案


问题的核心是 Swift 语言版本问题。您所指的项目太老了,无法在现代 Swift 中编译。由于布局管理器无法解析代码,这会产生各种次要问题。解决方案是更新代码以匹配编译器中的 Swift 版本。

特别是更改UIFontTextStyleUIFont.TextStyle和更改Notification.Name.UIContentSizeCategoryDidChangeUIContentSizeCategory.didChangeNotification


推荐阅读