Nib awakefromNib() crashes - ios

I have a class with a label and a collectionView, here is my code.
class CardSensors: UIView {
#IBOutlet weak var botName: UILabel!
#IBOutlet weak var sensorsCollectionView: UICollectionView!
var viewModel: NewsFeedViewModel! {
didSet {
setUpView()
}
}
override func awakeFromNib() {
super.awakeFromNib()
let nibName = UINib(nibName: "SensorCollectionViewCell", bundle:nil)
sensorsCollectionView.register(nibName, forCellWithReuseIdentifier: "SensorCollectionViewCell")
// Initialization code
}
func setUpView() {
botName.text = viewModel.botName
}
}
Obviously my cell has the correct Id and the correct reuse identifier.
And when I try to call the nib like this.
let sensorView = CardSensors()
sensorView.awakeFromNib()
I get Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value. I tried to force the values but I always get some errors.
What am I doing wrong?

As others have mentioned you should not call awakeFromNib() manually, it is something similar to how viewDidLoad() and viewWillAppear() get called automatically, the OS will fire it to let you know that your view has been loaded.
To initialize your view you could use the following static function, that allows you to call on the class to create a new instance of your CardSensors.
class CardSensors: UIView {
#IBOutlet weak var botName: UILabel!
#IBOutlet weak var sensorsCollectionView: UICollectionView!
var viewModel: NewsFeedViewModel! {
didSet {
setUpView()
}
}
static func loadFromNib() -> CardSensors {
return Bundle.main.loadNibNamed("CardSensors", owner: nil, options: nil)?.first as! CardSensors
}
override func awakeFromNib() {
super.awakeFromNib()
sensorsCollectionView.register(nibName, forCellWithReuseIdentifier: "SensorCollectionViewCell")
}
func setUpView() {
botName.text = viewModel.botName
}
}
let sensorView = CardSensors.loadFromNib()

You shouldn't call awakefromNib by yourself because awakefromNib will be called after you init your view by using UINib or load Nib from Bundle.main.loadNibNamed.
You can fix your error by using this:
class CardSensors: UIView {
#IBOutlet weak var botName: UILabel!
#IBOutlet weak var sensorsCollectionView: UICollectionView!
var viewModel: NewsFeedViewModel! {
didSet {
setUpView()
}
}
override init CardSensors() {
super.init()
let nibName = UINib(nibName: "SensorCollectionViewCell", bundle:nil)
sensorsCollectionView.register(nibName, forCellWithReuseIdentifier: "SensorCollectionViewCell")
// Initialization code
}
func setUpView() {
botName.text = viewModel.botName
}
}

Related

How can I override the method of view in Controller?

I made a custom View Cell that want to reuse. I want to add action to button in customView, that show side menu. So I wrote a code ReusableCustomView.swift like below.
class ResuableCustomView: UIView {
let nibName = "ReusableCustomView"
#IBOutlet weak var categoryMenuBTn: UIButton!
#IBOutlet weak var containerView: UIStackView!
func showMenu(){
print("tapped")
}
#IBAction func menuBtnClicked(_ sender: UIButton) {
self.showMenu()
}
#IBAction func buttonTap(_ sender: UIButton) {
print("Tappedd")
}
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)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
showing SideMenu Code is like below.
func showSlideMenu(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sideMenuViewController: SideMenuViewController = storyboard.instantiateViewController(withIdentifier: "SideMenuViewController") as! SideMenuViewController
let menu = CustomSideMenuNavigation(rootViewController: sideMenuViewController)
present(menu, animated: true, completion: nil)
}
The customized view is added to the storyboard and the ui is coming out well, and I want to override showMenu function so that i can show the side menu.
How Can I Override that function by code? I'd appreciate it if you could let me know.
ViewController code is below:
class categoryToViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
storyBoard image that adopts ResuableCustomView Class
ReusableCell.xib image
You can directly add the button action menuBtnClicked inside the categoryToViewController since the ReusableCustomView is placed inside this ViewController.
class categoryToViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func menuBtnClicked(_ sender: Any) {
print("pressed")
}
}
first you better inherit from UIControll instead of UIView.
Because you can get the event.
1- change define a class to this line:
class ResuableCustomView: UIControl { ... }
2- add to UIView to custom UIViewController and sed Custom class to ResuableCustomView:
3- create function in ViewController for get Event:
#IBAction private func customViewTapped(_ sender: ResuableCustomView) {
print("hello my friend :-)")
}
4- inside ResuableCustomView class set Action by append this line to your function:
self.sendActions(for: .touchUpInside)
this line send event for use.
Here I used type touchUpInside.
change your showMenu function to below code:
func showMenu(){
// set here callBack
self.sendActions(for: .touchUpInside) // and create event function with touchUpInside type
print("tapped")
}
5- now back to storyboard and connect IBAction to callBack like This Picture:
run and click on button and see print like this:
all code for CustomView:
// inheritance from UIControl instead of UIView
class ResuableCustomView: UIControl {
let nibName = "ReusableCustomView"
#IBOutlet weak var categoryMenuBTn: UIButton!
#IBOutlet weak var containerView: UIStackView!
func showMenu(){
// set here callBack
self.sendActions(for: .touchUpInside) // and create event function with touchUpInside type
print("tapped")
}
#IBAction func menuBtnClicked(_ sender: UIButton) {
self.showMenu()
}
#IBAction func buttonTap(_ sender: UIButton) {
print("Tappedd")
}
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)
}
func loadViewFromNib() -> UIView? {
let nib = UINib(nibName: nibName, bundle: nil)
return nib.instantiate(withOwner: self, options: nil).first as? UIView
}
}
all code for ViewController:
class ViewController: UIViewController {
#IBOutlet weak var customViewCell: ResuableCustomView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction private func customViewTapped(_ sender: ResuableCustomView) {
print("hello my friend :-)")
}
}

Make ViewController become a listener of a button clicked, located inside a custom view which located inside a TableViewCell xib?

I have a ViewController which holds a UITableView.
I created a UITableViewCell class named - CustomTableViewCell and connected it to a xib file with the same name. Inside this xib file I have a custom view named - CustomTextFieldView, and this custom view has a button in it, named - listButton.
My goal is that the ViewController will be a listener of the listButtonPressed action so that later help me to expand and collapse the table view cell every time this button pressed.
This is what i have tried
But I got exception when the relevant button clicked
Thanks in adavanced
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var customView: CustomTextFieldView!
#IBOutlet weak var label: UILabel!
static let identifier = "CustomTableViewCell"
static func nib() -> UINib {
return UINib(nibName: "CustomTableViewCell", bundle: nil)
}
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configure(withCell cell : PTTableModel) {
self.customView.initView(labelText: cell.label, placeHolder: cell.label, type: .name, hasList: cell.hasList)
}
}
protocol CustomTextFieldDelegate : class {
func didPressButton(button: UIButton)
}
class CustomTextFieldView: UIView {
#IBOutlet weak var listButton: UIButton!
#IBOutlet weak var bottomLine: UIView!
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var topLabel: UILabel!
#IBOutlet var contenView: UIView!
var delegate : CustomTextFieldDelegate!
static let identifier = "CustomTextFieldView"
static func nib() -> UINib {
return UINib(nibName: "CustomTextFieldView", bundle: nil)
}
override init(frame: CGRect) {
super.init(frame : frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
#IBAction func listButtonClicked(_ sender: Any) {
delegate.didPressButton(button: listButton)
}
}
class PetProfileDeatilsViewController: BaseUiViewController, UITableViewDelegate, UITableViewDataSource, CustomTextFieldDelegate {
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var nextButton: UIButton!
private var cells = ViewModel.createTableSction()
override func viewDidLoad() {
super.viewDidLoad()
headerView.initView(mainLabel: "Create", subLabel: "a profile")
let vc = CustomTextFieldView()
vc.delegate = self
self.view.addSubview(vc)
tableView.register(CustomTableViewCell.nib(), forCellReuseIdentifier: CustomTableViewCell.identifier)
}
func didPressButton(button: UIButton) {
print("worked")
}

Swift Delegate returns unexpectedly found nil while unwrapping an Optional value

Setting up my delegate within the protocol continues to throw nil. I have attempted numerous approaches suggested in other posts. I am attempting to get my protocol + delegate up and running, however, unable to solve why it continues to throw nil.
Force unwrapping, calling the delegate from various locations in the file, removing & adding Weak Var.
List View:
protocol MixPlayer : class {
func playMix(message: String)
}
class IssueViewController: UIViewController {
#IBOutlet weak var issueCollection: UICollectionView!
#IBOutlet weak var issueImage: UIImageView!
var viewController: ViewController?
var collectionViewtitle: String?
var mixImageName: String?
var mixList: [[String: String]]!
weak var mixDelegate: MixPlayer?
override func viewDidLoad() {
super.viewDidLoad()
issueCollection.dataSource = self
issueCollection.delegate = self
}
}
....
extension IssueViewController: UICollectionViewDelegate, UICollectionViewDataSource {
....
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if let url = mixList[indexPath.row]["url"] {
mixDelegate?.playMix(message: url)
}
}
}
View Controller:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var mainContainer: UIView!
#IBOutlet weak var playerEmbedView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
let secondVC = IssueViewController()
secondVC.mixDelegate = self
}
}
extension ViewController: MixPlayer {
func playMix(message: String) {
print(message)
}
}
Any attempt at calling
mixDelegate?.playMix(message: url)
Is unsuccessful. Currently I'm just trying to log basic print statements.
Probably your secondVC inside the ViewController gets deallocated. Make that a property in your ViewController.
class ViewController: UIViewController {
#IBOutlet weak var mainContainer: UIView!
#IBOutlet weak var playerEmbedView: UIView!
lazy var secondVC: IssueViewController = {
let secondVC = IssueViewController()
secondVC.mixDelegate = self
return secondVC
}()
override func viewDidLoad() {
super.viewDidLoad()
}
...
}
To know if your class gets deallocated, add a deinit with a print statement on it.
deinit {
print("Deallocated")
}

EXC_BAD_INSTRUCTION When Passing UICollectionView Cell Data to Different ViewController

I have a UICollectionView that I am populating based on Firebase data. I have created custom cells that populate the UICollectionView:
import UIKit
import Material
class PollCell: CollectionViewCell {
var key: String? {
get {
return self.key
}
}
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var pollQuestion: UILabel!
public required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
I am attempting to access the pollQuestion variable of the clicked cell in the UICollectionView and pass it to another ViewController:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "toPoll" {
let pollViewController = segue.destination as! PollController
if let cell = sender as? PollCell {
pollViewController.passLabel.text = cell.pollQuestion.text
}
}
}
PollController:
import UIKit
class PollController: UIViewController {
#IBOutlet weak var passLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
UPDATE: I have revised the code and am now receiving the error
The app is crashing at runtime, and I am trying to resolve:
The crash occurs because the outlet passLabel is not connected yet when prepare(for segue is called.
You have to declare a (temporary) variable in PollController and set the label in viewDidLoad
class PollController: UIViewController {
#IBOutlet weak var passLabel: UILabel!
var pass = ""
override func viewDidLoad() {
super.viewDidLoad()
passLabel.text = pass
}
...
In prepare(for segue set the variable rather than the text property of the label:
let pollViewController = segue.destination as! PollController
if let cell = sender as? PollCell {
pollViewController.pass = cell.pollQuestion.text
}
}
Note: It's not recommended to gather information from the view (cell). Get the index path and read the information from the model (data source array).
Instead of calling cellForItem, which gives you a new cell, you should use the cell that is passed to you as sender.
if let cell = sender as? PollCell {
pollViewController.passLabel.text = cell.pollQuestion.text
}

FirebaseUi - Cast value of UITableViewCell to custom class in swift

I can t seem to get the prototypereuseidentifier thing on firebaseUI. If I add a prototypecell, I can only give it a cellidentifier
In my following code, my IBoutlets linked to my custom cell return nil.
here s my code :
func loadData() {
self.dataSource = FirebaseTableViewDataSource(ref: refpost, cellClass: MainWitnessTableViewCell.self, cellReuseIdentifier: "<RIcell>", view: self.tableView)
self.dataSource.populateCellWithBlock { (cell: UITableViewCell, obj: NSObject) -> Void in
let snap = obj as! FDataSnapshot
print(cell)
let mycell = cell as! MainWitnessTableViewCell
let keyy: String = (snap.value.objectForKey("author") as? String)!
mycell.postContent.text = keyy
print (mycell.postContent.text)
}
self.tableView.dataSource = self.dataSource
}
here, mycell.postContent.text returns nil, is there any sorcery that keeps blinding me ? :)
sincerely
Yann
I think you should change
cellReuseIdentifier: "<RIcell>"
to
cellReuseIdentifier: "RIcell"
# jonas : here s the cell class
class MainWitnessTableViewCell: UITableViewCell, UITextFieldDelegate {
#IBOutlet weak var cellImage: UIImageView!
#IBOutlet weak var postOwner: UILabel!
#IBOutlet weak var postDate: UILabel!
#IBOutlet weak var postContent: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
postContent.text = ""
postOwner.text = ""
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

Resources