Using a variable from a separate view controller in Swift - ios

I am trying to get input from a text field and display that on a label in a separate view controller.
I am trying to get the partyID from PartyViewController:
class PartyViewController: UIViewController {
// CALLS LOGIN VC
var LoginViewController: LoginViewController?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var partyID: UITextField!
Into my second view controller:
class GuestPartyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBOutlet weak var PartyViewController.partyID:
UILabel!
This gives me several errors..
Class 'GuestPartyViewController' has no initializers
Consecutive declarations on a line must be separated by ';'
Expected declaration
Type annotation missing in pattern

You can access variable like this:
class PartyViewController: UIViewController {
var partyID: Type = Value
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
Another controller
var GuestPartyViewController: PartyViewController = PartyViewController(nibName: nil, bundle: nil)
var getPartyId = GuestPartyViewController.partyID

Related

How to fix IBOutlet "unexpectedly found nil" error when binding data with RxSwift?

I want to bind my data of BehaviorRelay<[Data]> from my View Model class into a UITableView in my UIViewController class, but unfortunately I keep getting this error:
Unexpectedly found nil while implicitly unwrapping an Optional value: file project/ResultCell.swift, line 27
2021-04-17 15:06:32.497411+0700 project[5189:936745] Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file project/ResultCell.swift, line 27
Here's what I did (In my View Controller class):
private func setupUI() { // Called in viewDidLoad()
resultsTv.register(ResultCell.self, forCellReuseIdentifier: ResultCell.IDENTIFIER)
}
private func setupRxBindings() { // Called in viewDidLoad()
viewModel.results.asObservable().bind(to: resultsTv.rx.items(cellIdentifier: ResultCell.IDENTIFIER, cellType: ResultCell.self)) { row, element, cell in
cell.configureData(with: element)
}.disposed(by: disposeBag)
let query = searchTf.rx.text.observe(on: MainScheduler.asyncInstance).distinctUntilChanged().throttle(.seconds(1), scheduler: MainScheduler.instance).map { $0 }
query.subscribe(onNext: { [unowned self] query in
self.viewModel.search(query ?? "") // Everytime I search something, it gives me the error
}).disposed(by: disposeBag)
}
My View Model class:
fileprivate final class SearchVM {
var results = BehaviorRelay<[ModelData]>(value: [ModelData]())
init() { }
func search(_ query: String) {
// Get the data from a server and store it in the results property
}
}
My ResultCell.swift class:
class ResultCell: UITableViewCell {
static let IDENTIFIER = "ResultCell"
#IBOutlet weak var photoIv: UIImageView!
#IBOutlet weak var idLbl: UILabel!
#IBOutlet weak var nameLbl: UILabel!
#IBOutlet weak var miscLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
func configureData(with data: ModelData) {
idLbl.text = "ID: \(data.id ?? "")" // The line that causes the error
nameLbl.text = data.name
miscLbl.text = "\(data.gender), \(data.height), \(data.phone)"
}
}
In more detail, I'm making a search page that can show data based on the search results (I'm using an .xib files for both of my UIViewController and UITableViewCell files). Since I'm learning RxSwift I don't want to use any delegates and datasources for my UITableView. I'm guessing the error is because the cell was not loaded properly so the IBOutlets is not yet initialized. But I'm not sure how to solve the error. Is there anyway to solve this?
You have registered the cell class against your reuse identifier. This just instantiates your cell instances without any reference to your XIB file, and so the outlets are not connected.
You need to register the XIB file against the reuse identifier.
private func setupUI() { // Called in viewDidLoad()
resultsTv.register(UINib(nibName: "yourNib", bundle: nil), forCellReuseIdentifier: ResultCell.IDENTIFIER)
}

How to move data backward from third viewcontroller to first viewcontrlloer using notification center?

I have 3 view controller. I have passed object from first to second and second to third viewcontroller and now editing some data in third viewcontroller and trying send updated data object back to first viewcontroller using notification center. But I am not sure how or which method should i use to post notification which can pass data object to first viewcontrller.
For now I tried as following
// third view controller
import UIKit
protocol editContactDelegate: AnyObject {
func updateContact(contact: Contact)
}
class EditViewController: UIViewController {
#IBOutlet weak var lblName: UILabel!
#IBOutlet weak var lblPhoneNumber: UILabel!
#IBOutlet weak var lblEmailID: UILabel!
var editContact: Contact?
weak var delegate: editContactDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
lblName.text = editContact?.name
lblPhoneNumber.text = editContact?.phone
lblEmailID.text = editContact?.email
}
#IBAction func editContact(_ sender: AnyObject) {
///??? which method should i use to post object
NotificationCenter.default.post(name: NSNotification.Name("Test"), object: Contact(name: "abc", position: "xyz", email: "updated#gmail.com", phone: "updated number"))
}
}
//////////
// first view controller
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, editContactDelegate {
func updateContact(contact: Contact) {
print(contact.email)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.tableview.delegate = self
self.tableview.dataSource = self
tableview.register(UINib(nibName: "ContactCell", bundle: nil), forCellReuseIdentifier: "ContactCell")
NotificationCenter.default
.addObserver(self,
selector:#selector(NotificationAct(_:)),
name: NSNotification.Name ("Test"), object: nil)
}
#objc func NotificationAct(_ notification: NSNotification) {
var abc = notification. // how to get object from third viewcontroller ???
}
}
You need
let abc = notification.object as! Contact

Refresh Current View Controller Data Request when XIB Button Clicked

I want to make error handling pages to all of my view controller through, so when error fetching data error, it's not only showing dialog, but showing a XIB files that contain error message and button to refresh. Like this:
Here's the XIB Class code:
import UIKit
class ErrorMessage: UIView {
#IBOutlet weak var imageViewError: UIImageView!
#IBOutlet weak var labelError: UILabel!
#IBOutlet weak var buttonTryAgain: UIButton!
static var message: String?
override func awakeFromNib() {
labelError.text = ErrorMessage.message
}
#IBAction func didTapTryAgain(_ sender: Any) {
Dialog.showProgressDialog(info: "")
}
}
Here's my base controller code, who handling all the problem.
import Foundation
class BaseViewController: UIViewController {
var uiView = UIView();
override func viewDidLoad() {
}
func getErrorMessage(message:String) {
super.viewDidLoad()
ErrorMessage.message = message
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
self.view.addSubview(viewErrorMessage)
}
}
And here's how I call it in another class which I extend BaseViewController, so it can show the error problem globally, without I redeclared again the class:
func onFailedDeleteCart(errorMessage: String) {
getErrorMessage(message: errorMessage)
}
Right now I can pass the error message.
The problem is, I want the Refresh button refreshing current View Controller when I click it. Maybe calling current View Controller's viewDidLoad when I click it will be the nice logic but I don't know how to implement it in XIB class. Anyone can solve out this? Thank you!
Approach: 1
Step:1 Create closure for callback
typealias RefreshBlock = (()->())?
Step:2 Define closure in your UIView class
Step:3 Call closure if user tap refresh button
class ErrorMessage: UIView {
#IBOutlet weak var imageViewError: UIImageView!
#IBOutlet weak var labelError: UILabel!
#IBOutlet weak var buttonTryAgain: UIButton!
var refreshBlock:RefreshBlock!
static var message: String?
override func awakeFromNib() {
labelError.text = ErrorMessage.message
}
// Step : 3
#IBAction func didTapTryAgain(_ sender: UIButton) {
refreshBlock!()
}
}
Step:4 Assign value in closure when addSubview called
class BaseViewController: UIViewController {
override func viewDidLoad() {
}
func getErrorMessage(message:String) {
super.viewDidLoad()
ErrorMessage.message = message
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
viewErrorMessage.refreshBlock = {()
self.viewDidLoad()
print("Refresh Contents")
}
self.view.addSubview(viewErrorMessage)
}
}
Approach: 2
Pass your current UIViewController Reference into UIView class. Refer below code.
class ErrorMessage: UIView {
#IBOutlet weak var imageViewError: UIImageView!
#IBOutlet weak var labelError: UILabel!
#IBOutlet weak var buttonTryAgain: UIButton!
var currentVC:UIViewController!
static var message: String?
override func awakeFromNib() {
labelError.text = ErrorMessage.message
}
#IBAction func didTapTryAgain(_ sender: UIButton) {
currentVC.viewDidLoad()
}
}
class BaseViewController: UIViewController {
override func viewDidLoad() {
}
func getErrorMessage(message:String) {
super.viewDidLoad()
ErrorMessage.message = message
guard let viewErrorMessage = Bundle.main.loadNibNamed("ErrorMessage", owner: self, options: nil)?.first as? ErrorMessage else { return}
viewErrorMessage.currentVC = self
self.view.addSubview(viewErrorMessage)
}
}

Required initializers for a subclass of UIViewController

I've been attempting to follow a tutorial about creating a container view controller. It's in Objective-C. I want to convert it to Swift. I've found some of the same questions here, but I didn't get too much out of them.
Here's the code.
import UIKit
class ContainerViewController: UIViewController { // Class "ContainerViewController" has no initializers - That I know why.
// 'required' initializer 'init(coder:)' must be provided by a subclass of UIViewController
var currentDetailViewController: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
I've tried doing what both errors say, but still doesn't work.
The problem is: If you declare any stored properties without initial value, you must implement your own initializer to initialize them. see this document.
Like this:
var currentDetailViewController: UIViewController
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
currentDetailViewController = UIViewController()
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
convenience override init() {
self.init(nibName: nil, bundle: nil)
}
required init(coder aDecoder: NSCoder) {
currentDetailViewController = UIViewController()
super.init(coder:aDecoder)
}
But, I think this is not what you want.
The correct solution depends on where you initialize currentDetailViewController.
If you always initialize it within viewDidLoad, then you can declare it as an "Implicitly Unwrapped Optional"
var currentDetailViewController: UIViewController!
override viewDidLoad() {
super.viewDidLoad()
self.currentDetailViewController = DetailViewController()
}
otherwise, If currentDetailViewController can be nil, you should declare it as an "Optional"
var currentDetailViewController: UIViewController?

Understanding delegates in iOS programming

I am new to iOS programming and I'm trying to understand and begin implementing delegates to get information between view controllers and any other use they may have.
I've used this topic to get a little further, but I can't comment as i just created this account, so i can't ask a question on the post. I copied drewag's example but this line
#IBOutlet weak var delegate: ViewControllerBDelegate?
is giving me an error "IBOutlet property cannot have non-object type SecondViewControllerDelegate"
I deleted it and it runs but the information is not being sent between the two view controllers. I thought i was beginning to understand delegates but just getting them implemented is beginning to get frustrating. I've been at this for a few days now.
FirstViewController:
class FirstViewController: UIViewController, SecondViewControllerDelegate {
#IBOutlet weak var theMap: MKMapView!
func requiredText() -> String {
return "test"
}
SecondViewcontroller:
protocol SecondViewControllerDelegate {
func requiredText() -> String
}
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var delegate: SecondViewControllerDelegate?
#IBAction func decide(sender: AnyObject) {
if let actualDelegate = self.delegate {
self.label.text = actualDelegate.requiredText()
}
}
So my question simply is what am I doing wrong? I thought i followed the example correctly.
You need to declare SecondViewControllerDelegate like this:
#objc protocol SecondViewControllerDelegate {
func requiredText() -> String
}
This is just a quirk of the Swift compiler or the runtime. The #objc directive makes the compiler emit additional information about the protocol. At runtime, the program uses that information to verify the delegate implements the protocol's methods. Since these objects are loaded from a xib (or storyboard), the compiler can't verify it at compile time.
You do not set your actualDelegate = firstViewController,so actualDelegate is always nil.
If you use storyboard,set Identifier of firstViewController as "first"
then
override func viewDidLoad() {
super.viewDidLoad()
let storyboard = UIStoryboard(name: "Main", bundle: nil);
var firstview = storyboard.instantiateViewControllerWithIdentifier("first") as FirstViewController?;
self.delegate = firstview;
// Do any additional setup after loading the view, typically from a nib.
}

Resources