使用Xcode 9.3、Swift 4.1开发OS X Cocoa应用时的视图重复问题
解决Swift 2.0到4.1适配中的视图重复问题
作为同样啃过旧版Big Nerd Ranch书籍的开发者,太懂这种版本适配踩坑的痛苦了!结合你提到的骰子组件视图重复问题,大概率和Swift 4.1的API变更或者Xcode 9.3的视图生命周期差异有关,我给你梳理几个常见的排查方向:
1. 检查视图加载方式的变更
Swift 2.0到4.1中,Cocoa的视图加载逻辑有不少细节调整:
- 如果你是通过
init(frame:)或者init?(coder:)初始化骰子视图,要确认是否在重复调用初始化方法。比如旧版书中可能直接在viewDidLoad里多次实例化视图,而Swift 4.1中如果配合Auto Layout,重复添加会导致视图叠加。 - 检查
loadView方法:如果自定义了这个方法,要确保没有重复调用super.loadView()或者重复添加子视图,Swift 4.1对视图加载的时机控制更严格,不小心就会重复创建。
2. 排查Auto Layout相关的适配问题
旧版书中的Swift 2.0代码可能用了过时的Auto Layout API:
- 比如Swift 2.0中的
constraintWithItem(_:attribute:relatedBy:toItem:attribute:multiplier:constant:)在Swift 4.1中已经被替换成更简洁的NSLayoutConstraint(item:attribute:relatedBy:toItem:attribute:multiplier:constant:),如果复制旧代码没改对,可能导致视图布局异常,看起来像是重复渲染。 - 确认是否开启了
translatesAutoresizingMaskIntoConstraints:Swift 4.1中默认这个属性对于通过代码创建的视图是true,如果旧版代码依赖它为false的行为,会导致视图被重复布局。
3. 检查骰子点数变更的逻辑
实现点数变更时,常见的重复视图诱因:
- 如果每次变更点数都创建新的骰子视图而没有移除旧的,自然会出现叠加。正确的做法应该是更新现有视图的内容(比如更换图片、修改文本),而不是重新实例化。
- 检查
IBOutlet和IBAction的绑定:Xcode 9.3中如果不小心重复绑定了控件到代码,会导致同一个操作触发多次视图更新,看起来像是视图重复。
4. Swift版本差异的其他坑
- Swift 4.1中
@IBOutlet的可选性处理更严格:旧版Swift 2.0中可能用了隐式解包的!,而Swift 4.1中如果视图还没加载就访问,可能导致意外的视图重建。建议用weak var配合可选绑定来处理。 - 字符串API的变更:如果骰子点数是用字符串渲染的,Swift 2.0到4.1的字符串拼接、索引方式变了,要是处理不当可能导致视图显示异常,误以为是重复问题。
给你举个Swift 4.1中更新骰子点数的示例代码:
class DieView: NSView { var value: Int = 1 { didSet { // 更新视图内容,触发重绘 self.setNeedsDisplay(self.bounds) } } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // 绘制骰子点数的逻辑,注意Swift 4.1的语法细节 let text = "\(value)" let attributes: [NSAttributedString.Key: Any] = [ .font: NSFont.systemFont(ofSize: 24), .foregroundColor: NSColor.black ] text.draw(at: NSPoint(x: bounds.midX - 10, y: bounds.midY - 12), withAttributes: attributes) } }
在主视图控制器中,更新点数时直接修改现有视图的属性即可,不用重新创建视图:
@IBAction func rollDie(_ sender: NSButton) { dieView.value = Int.random(in: 1...6) }
如果还是没解决,你可以检查一下是否在viewWillAppear或者viewDidAppear里重复添加了视图——这两个方法的调用时机和Swift 2.0一致,但如果逻辑没处理好,比如每次页面出现都加一次视图,就会导致重复。
内容的提问来源于stack exchange,提问作者j2000lbs
相关产品推荐
相关产品推荐

