I have a BaseView class which is inherited from UIView like:
#IBDesignable class BaseView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I set this class for UILabel, UIButton and UITextField in storyboard.
Now, I have to recognise that which one of the UILabel, UIButton or UITextField is called the init?(coder aDecoder: NSCoder).
Is there anyway around this issue?
Update:
It seems that it's not possible to set custom class of type UIView to UILabel so there is no way around this issue.
I tried to test the class
if self is UILabel { }
But I get a compiler warning that cast from BaseView to unrelated UILabel always fail
if (self as UIView) is UILabel { }
clears the warning but is of no use.
So a question: you said "I set this class for UILabel, UIButton and UITextField in storyboard"
Could you detail what you did ?
How do you declare the IBOutlet ? BaseView ? What type do you assign in IB to the label ?
Because BaseView is not a subclass of UILabel, I could not declare the label as BaseView ?
Related
I've created a reusable xib file that contains a table and it's being loaded in a TableView.swift file like this:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
Bundle.main.loadNibNamed("TableView", owner: self, options: nil)
}
I'm only mentioning this to clarify that I am not confused about how to load the xib file
I can easily load the reusable view in my RootViewController.swift file by adding a view to the UIViewController and giving that view a custom class like this:
and then creating an outlet for that view like this:
So here is my question:
Why am I not able to simply add the view like this:
let tableViewView = TableView()
When I do, I get an error that I don't totally understand:
You need to override the frame initializer as well.
Assuming your TableView class is a UITableView subclass, it should look something like this:
class TableView: UITableView {
override init(frame: CGRect, style: UITableViewStyle) {
super.init(frame: frame, style: style)
// any additional setup code
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
// any additional setup code
}
}
Because you are trying to instantiate the table view programmatically, you need to give it an initializer for the frame, not only an initializer with a coder.
This question already has answers here:
Proper practice for subclassing UIView?
(4 answers)
Closed 6 years ago.
In my current project, I often create a UIView to put a grey rectangle on the view. I usually put white views first on the layout, and then set all of the border in the viewDidLoad(). Now I decided that I want to speed things up by writing a subclass that will automatically set the border of the view, and then set all those views to use that subclass. But I don't know where to put this code on the subclass:
self.layer.borderWidth = 2;
self.layer.borderColor = UIColor.grayColor().CGColor;
Do I put it on override init()? Do I need to override every version of init for the UIView? Or is there a better way to do this?
Thanks.
PS: if there's also any way to make that the border can be immediately shown on the storyboard design time (I think it has something to do with drawable but I don't understand at all about it), I'll be very grateful!
EDIT:
From the accepted answer, I get this answer: https://stackoverflow.com/a/33721647/3003927 which basically like this:
import UIKit
class MyView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
didLoad()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
didLoad()
}
convenience init() {
self.init(frame: CGRectZero)
}
func didLoad() {
//Place your initialization code here
self.layer.borderWidth = 2;
self.layer.borderColor = UIColor.grayColor().CGColor;
}
}
You need to create subclass of UIView and declare IBInspectable properties as per your needs in this class .
Try below links as example :
http://nshipster.com/ibinspectable-ibdesignable/
https://www.captechconsulting.com/blogs/ibdesignables-in-xcode-6-and-ios-8
There's a pretty detailed answer here:
Proper practice for subclassing UIView?
Basically, you should override:
init?(coder aDecoder: NSCoder) and init(frame: CGRect) as well as awakeFromNib(). Just call another function from there where you set the border.
In Identity Inspector, I want to set a custom class for my UIButton.
Thus I create my custom class that is a UIView but my custom class doesn't appears on the list.
Vice-versa, if I add a UIView, on the list appears most class included UIButton.
If UIButton is a subclass of UIView, and not a UIView is a UIButton,
why is it possible and why can't I use my UIView custom class for representing my UIButton?
I'm not really sure entirely what you mean but I'll have a go.
Your question ...
If UIButton is a subclass of UIView, and not a UIView is a UIButton, why it's possible and why I can't use my UIView custom class for representing my UIButton.
I believe you are saying...
UIButton is a subclass of UIView.
Your custom view is a subclass of UIView.
Why can't you set your UIButton to be your custom view?
Is that right?
If so, it's fairly clear. Just because they are derived from the same class does not mean they are related. A UILabel is also derived from UIView but is very different.
If you want to create a custom subclass of UIButton then your custom class should derive from UIButton...
You should have...
#interface YourSubclass: UIButton
Instead of...
#interface YourSubclass: UIView
Doing this will make the custom subclass appear in the Identity Inspector in Interface Builder.
You can create a custom subclass for a UIButton. Then set it as Custom Class for any button.
class CCButton: UIButton {
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func drawRect(rect: CGRect) {
// Drawing code
}
*/
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
createBorder()
}
required override init(frame: CGRect) {
super.init(frame: frame)
createBorder()
}
private func createBorder(){
//Define Layer
self.layer.cornerRadius = 8.0
self.layer.masksToBounds = true
}
}
This is a class that is supposed to change the font of a label dynamically, right in the Storyboard:
#IBDesignable class FlexibleLabel: UILabel {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.font = UIFont(name: "Brandon Grotesque", size: self.font.pointSize)
}
}
I assigned this class to some labels but I get this error:
Failed to update auto layout status: The agent crashed.
What can I do to fix this?
The first method which is called after the view is fully initialized from nib is UIView's awakeFromNib() method. You can override and use it to modify view's or subviews properties
To figure out why the agent crashed, select the FlexibleLabel instance in your storyboard and from the menu bar choose Editor > Debug Selected Views. If the problem is in your code, Xcode should put you in the debugger at the crash.
Xcode doesn't use init(coder:) to create views when editing a storyboard. It uses init(frame:), then sets the properties of the view using KVC (key-value coding).
The code below is used to manipulate and configure IB Outlets of a subclassed UICollectionViewCell.
The IB outlets in the class, however, are not yet connected at this stage.
Other SO posts like this one suggest using awakeFromNib to manipulate the IB outlets, but in all the answers, the problem deals with a custom XIB.
However, this subclass doesn't use a custom XIB.
Is it still right to use awakeFromNib to configure the IB outlets even if no custom XIB is used?
override init(frame: CGRect) {
super.init(frame: frame)
doInit(frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
doInit(frame)
}
private func doInit(frame: CGRect) {
}