iOS 自定义视图 - 非常奇怪的属性行为
iOS custom view - very weird properties behavior
使用 Swift 2.0
我正在尝试使用带有标签(不仅仅是标签)的自定义视图在屏幕上显示一些信息,所以我的想法是以编程方式将自定义视图添加到 ViewController 上的滚动视图, 并设置标签的文本(开始)
问题: 我只是不知道标签和我想设置标签文本的字符串都不为空,并且由于某种原因字符串最后得到 null.
所以我进行了广泛的调试以显示每个变量在每个时刻的状态,这让我更加困惑:
(这是 Xcode 的日志输出)
my init was called, fatura String value: Optional("random text")
init with coder was called
- On awake from Nib
Label outlet is NOT null
fatura String is null
view loaded from Nib was added
- On Setup
Label outlet is null
fatura String is NOT null
checking fatura String value from ViewController: Optional("random text")
- On ViewController's viewDidLoad
Label outlet is null
fatura String is NOT null
- On ViewController's viewWillAppear
Label outlet is null
fatura String is NOT null
- On Button touched action
Label outlet is NOT null
fatura String is null
我是 iOS 的新手,从事 android 开发多年,我想真正了解发生了什么,所以任何 good 文章和书籍也将受到欢迎。我在自定义视图上找到了很多东西,但它们都有些不同,所以我不知道该使用哪个,而且它们大多只是实现,没有任何解释。
问题:
为什么在加载 Nib 视图之前,vencimentoLb 标签的出口开始为 "not null"?
为什么 fatura 字符串为 null,在*我的 init 被调用后,它设置了?
*至少日志是这样告诉我的
为什么我的 fatura 字符串在 buttonClicked 操作上为空?
总结一下:如何让标签和字符串都不是空的,以便在标签上设置文本?
我知道有很多问题,所以非常感谢能回答其中的任何一个问题
"Solution" 发现:
调用 customview.view 以强制 outlets 实例化。那没有用(自定义视图除了我创建的视图成员外没有视图成员,调用那个没有区别)
自定义视图的代码:
class FaturaCard: UIView {
var view:UIView!
@IBOutlet var vencimentoLb: UILabel!
@IBOutlet var cardView: UIView!
var fatura:String?
init(string:String , frame:CGRect){
fatura = string
print("my init was called, fatura String value:",self.fatura)
super.init(frame: frame)
setup()
}
override init(frame: CGRect){
super.init(frame:frame)
print("init with frame was called")
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
print("init with coder was called")
}
@IBAction func onBotaoClicked(sender: AnyObject) {
print("\n - On Button touched action")
checksWhatsNull()
}
func setup(){
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
print("view loaded from Nib was added")
print("\n - On Setup")
checksWhatsNull()
}
func checksWhatsNull(){
if vencimentoLb == nil{
print("Label outlet is null")
}else{
print("Label outlet is NOT null")
}
if self.fatura == nil{
print("fatura String is null")
}else{
print("fatura String is NOT null")
}
}
override func awakeFromNib() {
super.awakeFromNib()
print("\n - On awake from Nib")
checksWhatsNull()
}
func loadViewFromNib() -> UIView{
let nib = UINib(nibName: "FaturaCard", bundle: nil)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
编辑:
自定义视图实例化代码:
var view2:FaturaCard!
override func viewDidLoad() {
super.viewDidLoad()
view2 = FaturaCard(string:"random text",frame: CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145))
print("checking fatura String value from ViewController:",view2.fatura)
self.scrollView.addSubview(view2)
print("\n - On ViewController's viewDidLoad")
view2.checksWhatsNull()
self.scrollView.contentSize.height=145*2
}
您的问题日志中有两个 init 语句的输出。
这意味着您正在加载自定义视图的两个实例。
您看到的日志来自不同的实例,具体取决于操作 - 值没有改变,您看到的是来自不同实例的值。
将 print(self)
添加到您的日志记录中应该可以清楚地说明这一点。
init(coder:)
将在您从笔尖或故事板创建视图时出现。您正在使用自定义初始化(您在日志中看到)创建视图,然后在 setUp
方法中创建视图的 second 实例,并将其保存在原来的。这是不对的。
我想您已经阅读了有关访问 view
以强制加载视图的内容,并尝试在此处执行此操作 - 这适用于视图 控制器 ,不适用于意见,并且根本不适用于您的情况。
您可能应该直接从笔尖创建视图,然后设置 fatura
属性 - 无法从问题中判断,但我假设您的出口是指向主视图本身而不是文件的所有者,因此您可以使用 nil 的所有者创建。
查看更新后的代码,您可能想要这样的东西。
而不是 viewDidLoad 中的这一行:
view2 = FaturaCard(string:"random text",frame: CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145))
使用这个:
let nib = UINib(nibName: "FaturaCard", bundle: nil)
view2 = nib.instantiateWithOwner(nil, options: nil)[0] as! FaturaCard
view2.frame = CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145)
view2.fatura = "Random Text"
从 nibs 加载视图很尴尬,理想情况下,您可以将这些东西放在 FaturaCard
上的 class 方法中,您还可以在其中传递框架和字符串。
所以,最终问题出在了 Interface Builder 上。
我在 nib 的主视图中的身份检查器上设置了自定义 Class 属性,而不是在文件所有者占位符中。
这在 FaturaCard 的视图中创建了一个 'FaturaCard' 自定义视图的实例,因此一次创建了两个实例(如 jrturton 的回答所述),第二个实例由 init(coder:) 初始化,这造成了所有的麻烦。
这是一个初学者的错误,一个非常令人困惑的错误。
使用 Swift 2.0
我正在尝试使用带有标签(不仅仅是标签)的自定义视图在屏幕上显示一些信息,所以我的想法是以编程方式将自定义视图添加到 ViewController 上的滚动视图, 并设置标签的文本(开始)
问题: 我只是不知道标签和我想设置标签文本的字符串都不为空,并且由于某种原因字符串最后得到 null.
所以我进行了广泛的调试以显示每个变量在每个时刻的状态,这让我更加困惑: (这是 Xcode 的日志输出)
my init was called, fatura String value: Optional("random text")
init with coder was called
- On awake from Nib
Label outlet is NOT null
fatura String is null
view loaded from Nib was added
- On Setup
Label outlet is null
fatura String is NOT null
checking fatura String value from ViewController: Optional("random text")
- On ViewController's viewDidLoad
Label outlet is null
fatura String is NOT null
- On ViewController's viewWillAppear
Label outlet is null
fatura String is NOT null
- On Button touched action
Label outlet is NOT null
fatura String is null
我是 iOS 的新手,从事 android 开发多年,我想真正了解发生了什么,所以任何 good 文章和书籍也将受到欢迎。我在自定义视图上找到了很多东西,但它们都有些不同,所以我不知道该使用哪个,而且它们大多只是实现,没有任何解释。
问题:
为什么在加载 Nib 视图之前,vencimentoLb 标签的出口开始为 "not null"?
为什么 fatura 字符串为 null,在*我的 init 被调用后,它设置了? *至少日志是这样告诉我的
为什么我的 fatura 字符串在 buttonClicked 操作上为空?
总结一下:如何让标签和字符串都不是空的,以便在标签上设置文本?
我知道有很多问题,所以非常感谢能回答其中的任何一个问题
"Solution" 发现:
调用 customview.view 以强制 outlets 实例化。那没有用(自定义视图除了我创建的视图成员外没有视图成员,调用那个没有区别)
自定义视图的代码:
class FaturaCard: UIView {
var view:UIView!
@IBOutlet var vencimentoLb: UILabel!
@IBOutlet var cardView: UIView!
var fatura:String?
init(string:String , frame:CGRect){
fatura = string
print("my init was called, fatura String value:",self.fatura)
super.init(frame: frame)
setup()
}
override init(frame: CGRect){
super.init(frame:frame)
print("init with frame was called")
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
print("init with coder was called")
}
@IBAction func onBotaoClicked(sender: AnyObject) {
print("\n - On Button touched action")
checksWhatsNull()
}
func setup(){
view = loadViewFromNib()
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
addSubview(view)
print("view loaded from Nib was added")
print("\n - On Setup")
checksWhatsNull()
}
func checksWhatsNull(){
if vencimentoLb == nil{
print("Label outlet is null")
}else{
print("Label outlet is NOT null")
}
if self.fatura == nil{
print("fatura String is null")
}else{
print("fatura String is NOT null")
}
}
override func awakeFromNib() {
super.awakeFromNib()
print("\n - On awake from Nib")
checksWhatsNull()
}
func loadViewFromNib() -> UIView{
let nib = UINib(nibName: "FaturaCard", bundle: nil)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
编辑:
自定义视图实例化代码:
var view2:FaturaCard!
override func viewDidLoad() {
super.viewDidLoad()
view2 = FaturaCard(string:"random text",frame: CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145))
print("checking fatura String value from ViewController:",view2.fatura)
self.scrollView.addSubview(view2)
print("\n - On ViewController's viewDidLoad")
view2.checksWhatsNull()
self.scrollView.contentSize.height=145*2
}
您的问题日志中有两个 init 语句的输出。
这意味着您正在加载自定义视图的两个实例。
您看到的日志来自不同的实例,具体取决于操作 - 值没有改变,您看到的是来自不同实例的值。
将 print(self)
添加到您的日志记录中应该可以清楚地说明这一点。
init(coder:)
将在您从笔尖或故事板创建视图时出现。您正在使用自定义初始化(您在日志中看到)创建视图,然后在 setUp
方法中创建视图的 second 实例,并将其保存在原来的。这是不对的。
我想您已经阅读了有关访问 view
以强制加载视图的内容,并尝试在此处执行此操作 - 这适用于视图 控制器 ,不适用于意见,并且根本不适用于您的情况。
您可能应该直接从笔尖创建视图,然后设置 fatura
属性 - 无法从问题中判断,但我假设您的出口是指向主视图本身而不是文件的所有者,因此您可以使用 nil 的所有者创建。
查看更新后的代码,您可能想要这样的东西。
而不是 viewDidLoad 中的这一行:
view2 = FaturaCard(string:"random text",frame: CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145))
使用这个:
let nib = UINib(nibName: "FaturaCard", bundle: nil)
view2 = nib.instantiateWithOwner(nil, options: nil)[0] as! FaturaCard
view2.frame = CGRect(x: 00, y:145, width: scrollView.bounds.size.width, height: 145)
view2.fatura = "Random Text"
从 nibs 加载视图很尴尬,理想情况下,您可以将这些东西放在 FaturaCard
上的 class 方法中,您还可以在其中传递框架和字符串。
所以,最终问题出在了 Interface Builder 上。
我在 nib 的主视图中的身份检查器上设置了自定义 Class 属性,而不是在文件所有者占位符中。 这在 FaturaCard 的视图中创建了一个 'FaturaCard' 自定义视图的实例,因此一次创建了两个实例(如 jrturton 的回答所述),第二个实例由 init(coder:) 初始化,这造成了所有的麻烦。
这是一个初学者的错误,一个非常令人困惑的错误。