在 Xcode 9 / Swift 4 中不再可以访问原生 UIKit 元素的子视图?

Posted

技术标签:

【中文标题】在 Xcode 9 / Swift 4 中不再可以访问原生 UIKit 元素的子视图?【英文标题】:Native UIKit elements' subviews are no longer accessible in Xcode 9 / Swift 4? 【发布时间】:2017-08-04 02:12:40 【问题描述】:

故事:

所以我正在研究如何隐藏UIPickerView 的选择指示器,我看到some SO threads 有一个解决方法。

但是,当我尝试在 Xcode 9(beta 4)和 Swift 4 中使用它时,我发现它不起作用。经过进一步检查,我意识到每当我打电话给 myPickerView.subviews 时,我的计数都是 0。现在这很奇怪,因为它显然以前像其他线程所建议的那样工作过。

我使用调试视图层次结构工具进行了检查,似乎子视图结构没有改变,older threads 似乎也有 3 个子视图。但由于某种原因,我无法访问它们。但令人难以置信的是,如果我将语言设置为 Swift 3.2 并在 ios 9.0 上运行相同的项目,我仍然会遇到相同的错误。所以我无法真正说出变化似乎起源于何时何地。不幸的是,我没有旧版本的 xcode 可以测试了。

同样的事情似乎发生在多个 UIKit 元素上,但不是全部。完整列表在这篇文章的末尾。我已经尽量做到全面,如果我遗漏了什么,请随时告诉我。

我知道解决此问题的正确方法是制作我自己的 UIScrollView 并对其进行自定义,但是对于将来的使用和其余元素,任何人都知道是否有解决方法来解决已经是解决方法的问题?

仍有子视图的元素:

UISwitch : 1 个子视图 UITextView : 1 个子视图 UIDatePicker : 1 个子视图 UITableView : 1 个子视图 UISearchBar : 1 个子视图 UIProgressView : 2 个子视图 UIStepper:3 个子视图

没有子视图的元素:

UISegmentedControl UIPickerView UITextField UISlider UIPageControl

用于获得这些结果的源代码:

    let tableView        = UITableView()
    let pickerViewHere   = UIPickerView()
    let segmentedControl = UISegmentedControl()
    let textField        = UITextField()
    let slider           = UISlider()
    let switchUI         = UISwitch()
    let progressView     = UIProgressView()
    let pageControl      = UIPageControl()
    let stepper          = UIStepper()
    let textView         = UITextView()
    let datePicker       = UIDatePicker()
    let searchBar        = UISearchBar()
    
    
    print("switchUI has: (\(switchUI.subviews.count)) subviews")
    print("progressView has: (\(progressView.subviews.count)) subviews")
    print("stepper has: (\(stepper.subviews.count)) subviews")
    print("textView has: (\(textView.subviews.count)) subviews")
    print("datePicker has: (\(datePicker.subviews.count)) subviews")
    print("tableView has: (\(tableView.subviews.count)) subviews")
    print("segmentedControl has: (\(segmentedControl.subviews.count)) subviews")
    print("pickerViewHERE has: (\(pickerViewHere.subviews.count)) subviews")
    print("pickerView has: (\(pickerView.subviews.count)) subviews")
    print("searchBar has: (\(searchBar.subviews.count)) subviews")
    print("textField has: (\(textField.subviews.count)) subviews")
    print("slider has: (\(slider.subviews.count)) subviews")
    print("pageControl has: (\(pageControl.subviews.count)) subviews")

【问题讨论】:

如果你想要旧版本的 xcode,你可以从苹果的开发者门户下载它。他们都在那里。但是,您可能只需将部署目标更改为 iOS 10,因为这样您就不会使用新的 API 问题是我的计算机上没有存储空间,这就是为什么我删除了我的(稳定)版本的 Xcode 8! 【参考方案1】:

显然,在 iOS 11 中,UIPickerView 在其 layoutSubviews 方法中创建其子视图。大概其他视图也懒惰地创建了它们的子视图。

测试代码:

import UIKit

class ViewController: UIViewController 
    let pickerView = MyPickerView()

    override func viewDidLoad() 
        super.viewDidLoad()
        view.addSubview(pickerView)
        pickerView.frame = view.bounds
    


class MyPickerView: UIPickerView 
    override func layoutSubviews() 
        print("before layoutSubviews: \(subviews.count)")
        super.layoutSubviews()
        print("after layoutSubviews: \(subviews.count)")
    

输出:

before layoutSubviews: 0
after layoutSubviews: 3
before layoutSubviews: 3
after layoutSubviews: 3
before layoutSubviews: 3
after layoutSubviews: 3

【讨论】:

谢谢!任何线索为什么如果我在模拟器上的 iOS 9.0 上运行它会得到相同的结果?编译的 SDK 是变了还是怎么了? 另外,作为对 rob 答案的注释,如果您在 viewDidLoad 中调用 layoutSubviews(),并且您已经在情节提要中创建了 UIPickerView,则不会发生任何事情。您必须等到情节提要或手动调用 addSubview()

以上是关于在 Xcode 9 / Swift 4 中不再可以访问原生 UIKit 元素的子视图?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift 4 和 Xcode 9 获取 JSON 数据

无法在 Alamofire 中禁用缓存(Xcode 9 - swift 4)

Xcode 9 Swift 4 Playgrounds UIGestureRecognizer 不工作

在 swift 4 和 Xcode 9 中解码 ExpandableTableView 的嵌套 json 数组

Audiokit 4.9.5 在 xcode 11.4 + swift 5.2 中崩溃,没有有用的错误消息

在一个视图控制器中使用不同的按钮上传多个图像(iOS、Xcode 9、Swift 4)