同一ViewController中类间字符串传递及setupPaths取值异常问题
问题描述
我创建了一个包含两个类的ViewController,代码如下:
import UIKit class ViewController: UIViewController { @IBOutlet weak var Viewholder: UIImageView! var txt:String? override func viewDidLoad() { super.viewDidLoad() let vv= TestView(frame: Viewholder.frame) view.addSubview(vv) txt= "hello" let rr = TestView(frame: self.view.frame,textvalue:txt!) rr.colour = "" // set value } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } } class TestView: UIView { var textvalue:String? init(frame: CGRect,textvalue) { self.textvalue= textvalue super.init(frame: frame) self.sharedLayout() } override init(frame: CGRect) { super.init(frame: frame) self.frame = frame self.setupPaths() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func sharedLayout() { print(textvalue!) // works here } func setupPaths() { print(textvalue!) // doesnt work here (displays nil) } }
我希望让setupPaths方法中的textvalue能获取到正确的值,以此来修改标签文本,但目前setupPaths方法返回null,无法实现标签文本修改,该如何解决?
解决方案
咱们先把问题根源捋清楚:
你看TestView的两个初始化逻辑是脱节的:
- 带
textvalue参数的初始化方法,只调用了sharedLayout(),压根没触发setupPaths(); - 只传
frame的初始化方法,虽然调用了setupPaths(),但这个流程里完全没给textvalue赋值,它自然是nil。
要让setupPaths()能拿到正确的textvalue,咱们得把初始化流程统一起来,让所有创建TestView的路径都能正确传递值并调用必要方法,给你两个实用方案:
方案一:统一初始化入口,确保所有路径走相同逻辑
修改TestView的初始化代码,把所有初始化后的设置都放到一个公共方法里,不管用哪种方式创建视图,都会执行这个方法:
class TestView: UIView { var textvalue: String? // 带textvalue的初始化方法 init(frame: CGRect, textvalue: String?) { self.textvalue = textvalue super.init(frame: frame) commonSetup() // 调用公共设置方法 } // 默认的frame初始化方法 override init(frame: CGRect) { super.init(frame: frame) commonSetup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonSetup() // 适配xib/storyboard初始化 } // 把sharedLayout和setupPaths统一放到这里调用 private func commonSetup() { sharedLayout() setupPaths() } func sharedLayout() { // 别用强制解包,可选绑定更安全 if let text = textvalue { print(text) } } func setupPaths() { // 现在这里能拿到正确的textvalue了 if let text = textvalue { print("setupPaths获取到文本:\(text)") // 这里就可以修改你的标签文本,比如: // myLabel.text = text } } }
这样不管你用TestView(frame:)还是TestView(frame:textvalue:)创建实例,setupPaths()都会被调用,初始化时传了textvalue就能直接拿到值,没传也不会因为强制解包崩溃。
方案二:用属性观察者,值变化时自动更新UI
如果你希望后续修改textvalue时,标签文本也能自动更新,可以把textvalue改成带属性观察者的变量:
class TestView: UIView { // 当textvalue的值变化时,自动调用setupPaths var textvalue: String? { didSet { setupPaths() } } init(frame: CGRect, textvalue: String?) { self.textvalue = textvalue super.init(frame: frame) sharedLayout() setupPaths() // 初始化时先调用一次 } override init(frame: CGRect) { super.init(frame: frame) sharedLayout() setupPaths() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } func sharedLayout() { print(textvalue ?? "无文本") } func setupPaths() { if let text = textvalue { print("setupPaths更新文本:\(text)") // 更新标签文本 // myLabel.text = text } } }
这样不仅初始化时setupPaths()能拿到值,后续执行rr.textvalue = "新内容"时,setupPaths()会自动触发,帮你更新标签。
最后提两个小细节:
- Swift代码规范里变量名用小驼峰,比如
Viewholder改成viewHolder,可读性更好; - 尽量避免用强制解包
!,用if let或者空合运算符??,能减少崩溃风险。
内容的提问来源于stack exchange,提问作者user9802387
相关产品推荐
相关产品推荐

