Error occurs when I set UITextField delegate.
My code is:
import UIKit
class UserAlertVC: UIView , UITextFieldDelegate {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
override init(frame: CGRect) {
super.init(frame: frame)
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
self.addBehavior()
}
func addBehavior (){
print("Add all the behavior here")
userNameTxtField.delegate = self
passwordTxtField.delegate = self
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
return true
}
func textFieldDidBeginEditing(textField: UITextField) {
}
#available(tvOS 10.0, *)
func textFieldDidEndEditing(textField: UITextField, reason: UITextFieldDidEndEditingReason) {
}
#IBAction func actionOnCancel(sender: UIButton) {
self .removeFromSuperview()
}
#IBAction func actionOnProceed(sender: UIButton) {
self .removeFromSuperview()
UserAlertVC.showAlertForUser()
}
#IBOutlet var userNameTxtField: UITextField!
#IBOutlet var passwordTxtField: UITextField!
static func showAlertForUser() {
let alert = NSBundle.mainBundle().loadNibNamed("KeyboardViewController", owner: self, options: nil)!.last as! UIView
let windows = UIApplication.sharedApplication().windows
let lastWindow = windows.last
alert.frame = UIScreen.mainScreen().bounds
lastWindow?.addSubview(alert)
}
}
Error message is:
fatal error: unexpectedly found nil while unwrapping an Optional value
I have used Custom Alert View using XIB.pls suggest any solution.
Firstly take a look at life cycle of the view. Depending on this it is possible to highlight that method awakeFromNib is quite suitable because:
The nib-loading infrastructure sends an awakeFromNib message to each
object recreated from a nib archive, but only after all the objects in
the archive have been loaded and initialized. When an object receives
an awakeFromNib message, it is guaranteed to have all its outlet and
action connections already established.
Make sure to put an #IBOutlet for the .Xib content view, also you need to add the Nib code. Last, make sure in your ViewController you set your UIView Outlet to be UserAlertVC and you add the awakeFromNib method. Please find attached the code. Let me know if you need further help.
Here is the code related to the .xib file.
import UIKit
class UserAlertVC: UIView, UITextFieldDelegate {
//MARK: - Outlets
#IBOutlet var contentView: UIView!
#IBOutlet var userNameTxtField: UITextField!
#IBOutlet var passwordTxtField: UITextField!
//MARK: - Loads
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
commonInit()
}
//MARK: - Functions
func commonInit() {
Bundle.main.loadNibNamed("UserAlertVC", owner: self, options: nil)
userNameTxtField.delegate = self
passwordTxtField.delegate = self
contentView.translatesAutoresizingMaskIntoConstraints = false
addSubview(contentView)
// add constraints programmatically
}
// add the rest of your code
}
Here is the code related to the ViewController.
class ViewController: UIViewController {
//MARK: - Outlets
#IBOutlet weak var userAlertVC: UserAlertVC!
//MARK: - Loads
override func viewDidLoad() {
super.viewDidLoad()
}
override func awakeFromNib() {
super.awakeFromNib()
}
}
Related
I have the following swift file which controls a xib file
import UIKit
protocol SelectProfile: class {
func selectionUp(id: Int, selected: Bool)
}
class Component: UIView {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var selection: UIView!
var selected: Bool = false
var profileId: Int = 6
weak var delegate: SelectProfile?
#IBAction func selProfile(_ sender: Any) {
selected = !selected
selection.isHidden = !selected
delegate?.selectionUp(id: profileId, selected: selected)
}
let nibName = "Component"
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
func commonInit() {
guard let view = loadViewFromNib() else { return }
view.frame = self.bounds
self.addSubview(view)
selection.isHidden = true
name.text = String(profileId)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
In my UIViewController where I want to interact with the component I have the following code (shortened for brevity)
import UIKit
class Home: UIViewController, SelectProfile {
#IBOutlet weak var profileComponent: Component!
func selectionUp(id: Int, selected: Bool) {
print(id, selected)
}
override func viewDidLoad() {
profileComponent.delegate = self
profileComponent.profileId = 2
}
}
My delegate works nicely and I'm able to change the values for IBOutlets but I can't pass a value to variables. This line doesn't pass the data to my xib profileComponent.profileId = 2.
It seems like I have an issue with initialization of the xib but I don't know how to fix it.
The viewDidLoad of controller is called after view's init, so when you change profileId as you do, it is changed, but not reflected anywhere.
I assume the following, at least, missed:
var profileId: Int = 6 {
didSet {
name.text = String(profileId)
// call delegate here if needed as well
}
}
I am trying to implement NSStackView with always the same custom view. So I have define my xib file, linked everything inside my class, associated the class, ... but I am sure I am missing something because the content inside the view don't appear. Thx very much for your help.
My storyboard:
My xib file:
The result when I run the below code:
My file is like :
class CustomView: NSView, NSTableViewDelegate, NSTableViewDataSource {
#IBOutlet weak var segmentControlOutlet: NSSegmentedControl!
#IBOutlet weak var tableViewOutlet: NSTableView!
}
class ViewController: NSViewController, NSStackViewDelegate {
#IBOutlet weak var stackViewOutlet: NSStackView!
override func viewDidLoad() {
super.viewDidLoad()
stackViewOutlet.delegate = self
let newView = CustomView()
stackViewOutlet.addArrangedSubview(newView)
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
}
I have found the answer, you need to initiate properly the view. To do so :
class CustomView: NSView, NSTableViewDelegate, NSTableViewDataSource {
#IBOutlet var viewOutlet: NSView!
#IBOutlet weak var segmentControlOutlet: NSSegmentedControl!
#IBOutlet weak var tableViewOutlet: NSTableView!
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
Bundle.main.loadNibNamed("CustomView", owner: self, topLevelObjects: nil)
addSubview(viewOutlet)
viewOutlet.frame = self.bounds
viewOutlet.autoresizingMask = [.height, .width]
}
required init?(coder: NSCoder) {
super.init(coder: coder)
Bundle.main.loadNibNamed("CustomView", owner: self, topLevelObjects: nil)
addSubview(viewOutlet)
viewOutlet.frame = self.bounds
viewOutlet.autoresizingMask = [.height, .width]
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
}
Please take car that when you load the nib name, "CustomView" is the name of your xib file ;)
I have a ViewControllerA and two custom alerts and I'm calling the first custom alert on the buttonclick action of the ViewControllerA.
In first custom alert I'm having a text field and a button.
When I click on the button action of first custom alert , I want to open the second custom alert and both alerts I want show on ViewControllerA.
The expected result is to show both the custom alerts on the single ViewControllerA
Please help me out to solve this problem
class ViewControllerA : UIViewController{
#IBAction func ViewControllerAButtonTapped(_ sender: Any) {
FirstCustomalert.instance.ShowAlert()
self.dismiss(animated: true, completion: nil)
}
}
class FirstCustomAlert : UIView{
#IBOutlet var parentView: UIView!
static let instance = FirstCustomAlert()
#IBOutlet weak var firstTextField: UITextField!
override init(frame: CGRect) {
super.init(frame: frame)
Bundle.main.loadNibNamed("FirstCustomAlert", owner: self, options: nil)
CommonInit()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func CommonInit(){
alertView.frame = CGRect(x: center.x, y: center.y, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
ParentView.autoresizingMask = [ .flexibleHeight , .flexibleWidth ]
}
func ShowAlert(){
UIApplication.shared.keyWindow?.addSubview(ParentView)
}
#IBAction func SubmitBittonTapped(_ sender: Any) {
SecondCustomAlert.instances.ShowAlerts()
}
}
class SecondCustomAlert : UIView{
#IBOutlet var parentView: UIView!
#IBOutlet weak var secondTextField: UITextField!
static let instances = SecondCustomAlert()
override init(frame: CGRect) {
super.init(frame: frame)
Bundle.main.loadNibNamed("SecondCustomAlert", owner: self, options: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func CommonInit(){
parentView.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
parentView.autoresizingMask = [.flexibleWidth , .flexibleHeight ]
}
func ShowAlerts(){
UIApplication.shared.keyWindow?.addSubview(parentView)
}
}
Firstly, there are a number of things you need to change:
Naming convention:
Your methods should be named with lowerCamelCase and only classes and objects should be CamelCase.
You are building a custom alert to be displayed from anywhere in the app. Since you are already using .xib, I would suggest that you refactor your alert into a ViewController and use present(viewController: animated:) with presentationStyle of .overCurrentContext. You can get the topViewController on the keyWindow which you have and call the present function. Then in your AlertViewController you can do separate animations to display the second view of the alert upon button click.
What you are trying to do now is put too much logic into a UIView, which is not best practise and it isn't very scalable. Plus it looks messy. You are trying to achieve something relatively simply but the current approach already creates 2 customs views and you are already encountering callback issues.
ADD:
class ViewControllerA : UIViewController{
#IBAction func ViewControllerAButtonTapped(_ sender: Any) {
let customAlert = CustomAlertViewController()
customAlert.modalPresentationStyle = .overCurrentContext
self.present(customAlert, animated: true, completion: nil)
}
}
I have XIB file in which there is class of type UIView, and I wont to load that XIB in root ViewController:
import UIKit
class ViewController: UIViewController {
// MARK: - Variables
// MARK: - IBOutlets
#IBOutlet private weak var mainStackView: UIStackView!
// MARK: - LifeCycle Methods
override func viewDidLoad() {
super.viewDidLoad()
if let view = CustomView.instanceFromNib() {
let view = CustomView.instanceFromNib() as! CustomView
mainStackView.addArrangedSubview(view)
mainStackView.addArrangedSubview(view)
mainStackView.addArrangedSubview(view)
}
}
}
import Foundation
import UIKit
class CustomView: UIView {
static let id = "CustomView"
#IBOutlet weak var backgroundImageView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
}
static func instanceFromNib() -> UIView {
return UINib(nibName: "UserReview", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! UIView
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
this class is not key value coding-compliant for the key backgroundImageView.'
Did you File owner for Xib file ?? assign CustomView class to Xib File's Owner
I have created a .xib and adding this xib to another view. I want to add a delegate method in that .xib file. Here is my code :
.xib file
import UIKit
protocol CustomCheckBoxWithCrossDelegate {
func deleteCustomCheckbox(itemToDelete: String)
}
class CustomCheckBoxWithCross: UIView {
#IBOutlet weak var radioButton: UIButton!
#IBOutlet weak var checkboxLbl: UILabel!
#IBOutlet weak var checkboxCrossBtn: UIButton!
var blockIndexForTheCrossButton: Int = 0
var delegate: CustomCheckBoxWithCrossDelegate!
override init(frame: CGRect) {
super.init(frame: frame)
loadViewFromNib ()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
loadViewFromNib ()
}
func loadViewFromNib() {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: "CustomCheckBoxWithCross", bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
view.frame = bounds
view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
self.addSubview(view);
}
#IBAction func crossBtnTapped(sender: AnyObject) {
print("Delegate --> \(delegate)")
delegate!.deleteCustomCheckbox("hello")
}
}
But in "crossBtnTapped" method I am getting nil value for that delegate.
can anyone please tell me what I am doing wrong?
You must have the instance of CustomCheckBoxWithCross in your other class, where you have implemented the protocol. Set delegate property of CustomCheckBoxWithCross instance to self in that file.
I ran to this error several times before, add if delegate is not nil condition.
#IBAction func crossBtnTapped(sender: AnyObject) {
if delegate != {
delegate!.deleteCustomCheckbox("hello")
}
}