可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I tried to start and go from Obj-C to Swift today and I was reading the documentation. I tried to create an easy IBOutlet in Swift and it constantly gave me those errors.
View Controller has no initialiser
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") }
IBOutletproperty has non-optional type 'UILabel'
and that constantly pops up with this code:
@IBOutlet var outputLabel : UILabel
but when I add an ! mark, it's running without errors like so
@IBOutlet var outputLabel : UILabel!
Same thing happens for IBActions...
回答1:
First of all get to know, what is actually !
and ?
- Use
?
: if the value can become nil in the future, so that you test for this.
- Use
!
: if it really shouldn't become nil in the future, but it needs to be nil initially.
@IBOutlet:
When you declare an outlet in Swift, the compiler automatically converts the type to a weak implicitly unwrapped optional and assigns it an initial value of nil
.
In effect, the compiler replaces @IBOutlet var name:
Type with @IBOutlet weak var name: Type! = nil
.
Xcode would change it and Force restrict on declare @IBOutlet
non option type variable , so following both kind of declaration for @IBOutlet
is Valid till date.
@IBOutlet var outputLabel : UILabel!
@IBOutlet var priceLabel : UILabel?
However, if you control drag an outlet for a label in beta 4 this happens:
@IBOutlet var priceLabel : UILabel! = nil
回答2:
Interface builder data is loaded after view controller has been initiated, so outlets cannot have value after initialisation. With implicitly unwrapped optional properties (outlets in this case) you promise that properties might be nil after object is initiated, but their value will be assigned later (after the load of nib or storyboard).
回答3:
That is correct. In Swift, a variable of type X cannot be nil, meaning it has to be initialized. This means that you must initialize either in a init
method, or inline initialize.
Generally, view controllers will declare variables of types that are optional - for example,
@IBOutlet var outputLabel : UILabel!
This means that you do not need to initialize the outputLabel
, and by default, it's value is nil
. This is the general pattern for IBOutlet
variables, as the variables are set outside of the init
method.
If you do not make your variables optional, you must initialize it. If you do not initialize inline, you must provide an init
method - hence the error that you are getting.
回答4:
As Stack allows Q and A style questions, I'll also put it into easier words. Just put the !
at the and of outlets guys. Thanks a lot for your help.
回答5:
The error
'required' initialized 'init(coder:)' must be provided by subclass of 'UIViewController'
suddenly started when I added
var start : NSDate
to a previously working subclass of UIViewController otherwise all made in IB.
Changing to
var start : NSDate?
fixed. It is such a surprising error (huh? init? coder?) for a simple edit someone starting an app could make long before they encounter coders or create their own init methods, that perhaps it helps to show explicitly that initialization need is not confined to IBOutlets. The answers above describe the root cause.
回答6:
When views or view controllers are initialized from an interface builder file, their outlets cannot be connected yet. They will only be connected after initialization, so they need to be optional. When any other code in the class is called after initialization, though, these outlets are guaranteed to be connected. This is why IBOutlets are always declared as implicitly unwrapped optionals.
回答7:
While it seems like XCode is blessing this behavior, it's still unsafe and you always keep in mind that you might want to make some Optionals.
While IB will initialize these for you, that doesn't guarantee they won't become nil later ... for example, if you need to remove an IBOutlet as a subview, or conditionally set a NSLayoutConstraint.isActive = false (which an annoyingly stealthy nil).