This is my class of a UIView:
class overlap: UIView{
init() {
super.init(frame: UIScreen.main.bounds)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
}
It should just fill up the screen. When I add the view in Storyboard with constraints pinned to the edges of the screen, it crashes when I launch the app. The error comes up as stated in the code above.
Creating and adding the subclass programmatically works with this init function:
override init(frame: CGRect) {
super.init(frame: frame)
}
But I want it reusable through Storyboard, without adding code. What is wrong with my code, and is it even possible what I want?
Thanks!
it crashes when I launch the app
Because that is what your code told it to do.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
fatalError means "crash me".
Related
I have a custom UICollectionViewCell that I use in two places throughout my project.
Both UICollectionViewCell's are the same apart from showing a UIButton. To reduce duplication of code I want to use the cell in both places but initialize one with a Boolean that determines if the button is shown or not.
I believe I need a convenience initializer to do this, however, I am getting the error;
'self' used before 'self.init' call or assignment to 'self'
Code:
class MediaSelectionCell: UICollectionViewCell {
var withDeleteButton = false
convenience init(showsDeleteButton: Bool) {
self.init(showsDeleteButton: withDeleteButton)
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
How can I resolve this?
Your collectionview cell initialization doesn't have a methods called self.init(showsDeleteButton: withDeleteButton) that why you are getting an error message.
As said in the comment, cells are reuseable. If you register cell with storyboard , required init?(coder: NSCoder) initialization methods called , If you register cell programatically override init(frame: CGRect) is called.
So I mean, If you use dequeueReusableCell you can not change the initialization method by hands.
I prefer to create a two classes to do what you want:
One for not showing button:
class MediaSelectionCell: UICollectionViewCell {
var withDeleteButton = false
override init(frame: CGRect) {
super.init(frame: frame)
// maybe adding constraint your bla bla
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func controlButton() -> Bool{
if withDeleteButton{
// show
return true
}else{
// hide
return false
}
}
}
One for showing button :
class MediaSelectionShowButton : MediaSelectionCell{
override init(frame: CGRect) {
super.init(frame: frame)
self.withDeleteButton = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And in your cell you can control and do what you want with it :
cell.controlButton()
You can’t use a convenience initializer for table view or collection view cells because the table view/collection view creates them by calling the designated initializer.
You have to add a property to your custom class and set it up to honor that property.
This is my class of a UIView:
class overlap: UIView{
init() {
super.init(frame: UIScreen.main.bounds)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
}
It should just fill up the screen. When I add the view in Storyboard with constraints pinned to the edges of the screen, it crashes when I launch the app. The error comes up as stated in the code above.
Creating and adding the subclass programmatically works with this init function:
override init(frame: CGRect) {
super.init(frame: frame)
}
But I want it reusable through Storyboard, without adding code. What is wrong with my code, and is it even possible what I want?
Thanks!
it crashes when I launch the app
Because that is what your code told it to do.
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
fatalError means "crash me".
I am creating a UIView subclass with the intention to force users to my required init method than the default one.
So for that, I have created a convenience method for this.
#available(*, unavailable, message: "init is unavailable.")
public override init(frame: CGRect) {
super.init(frame: frame)
}
required
convenience public init(withSomeParameters myParam:Type) {
self.init(frame: CGRect.zero)
//Doing something nice!
}
This works! However, when I try to init it's showing me two ways to initialize it. How to force the user to make use of custom init method?
You can make it private , so user must need to init Test class with withSomeParameters
class Test:UIView {
private override init(frame: CGRect) {
super.init(frame: frame)
}
convenience public init(withSomeParameters myParam:Type) {
self.init(frame: CGRect.zero)
//Doing something nice!
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Maybe you need to mark the coder initialiser as unavailable as well:
#available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Plus: remove the convenience from your initialiser, and call supers init(frame:)
public init(withSomeParameters myParam:Type) {
super.init(frame: .zero)
//Doing something nice!
}
As another example, here is some base UIView subclass I use in a lot of my projects that don't utilise storyboards:
class MXView: UIView {
init() {
super.init(frame: .zero)
}
// Storyboards are incompatible with truth and beauty.
#available(*, unavailable)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Subclass:
class CustomView: MXView {
init(someParameters params: Type) {
// Phase 1: store ivars.
super.init()
// Phase 2: Do something nice.
}
If you do it like that, users of CustomView will be forced to use init(someParamters:). init(frame:) is shadowed because init(someParameters:) is a non-convenience init.
I am trying to subclass UIVisualEffect but I am having issues implementing the correct init methods. So far I have this:
import UIKit
class BlurView: UIVisualEffect {
init(effect: UIVisualEffect?) {
super.init(effect)
print("Init 1 called")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
print("Init 2 called")
}
}
I am getting the error: "Missing the argument coder in the call". I have also tried:
import UIKit
class BlurView: UIVisualEffect {
init(effect: UIVisualEffect?) {
super.init()
print("Init 1 called")
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
print("Init 2 called")
}
}
This complains that I haven't implemented the init method. I tried doing this but still couldn't get it working. Any ideas how to go about implementing these methods? Thanks!
There is a typo, you want to subclass UIVisualEffectView, not UIVisualEffect.
They are different UIVisualEffectView inherits from UIView and apply the UIVisualEffect that you pass in. UIVisualEffect is just the effect.
class BlurView: UIVisualEffectView {
override init(effect: UIVisualEffect?) {
super.init(effect: effect)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I have the following class representing a button in my iOS 8 custom keyboard:
internal class KeyButton: UIButton {
required init(char: Character) {
super.init()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Since KeyButton is not initialised via storyboard the constructor (coder: NSCoder) would never be called.
The problem is that I am required to implement (coder: NSCoder) constructor, when I run the app I receive the exception plugin interrupted when instantiating KeyButton.
Why am I required to implement (coder: NSCoder) constructor although I instantiate everything programatically
It has nothing to do with the coder. UIButton's init() calls init(frame: CGRect), which you haven't implemented. Add the following, and you should be good to go...
override init(frame: CGRect ) {
super.init(frame: frame)
println("Button frame allocated")
}