Access variable in a function which is called from another class - ios

I have a class1 which is having many variable and also having one function within a class1.I am calling the function from another class class2.function triggered but i cannot access variable of class1.
here is the sample code
class ViewController: UIViewController {
var Flat:String?
var Flong:String?
var Tlat:String?
var Tlong:String?
override func viewDidLoad() {
super.viewDidLoad()
Flat = "flat value";
Flong="flong value";
Tlat="Tlat value";
Tlong="tlong value";
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func calculation()
{
print("origin_lat new\(Flat)")
print("origin_lng new\(Flong)")
print("dest_lat new\(Tlat)")
print("dest_lng new\(Tlong)")
}
}
I am calling calculation method from another class Collectionviewcell click function
var mycontroller : ViewController = ViewController()
mycontroller.calculation()
Why i could not access the values anyone help me?

You can also reach other controller's variables with defining global variables like this way:
class Class1ViewController: UIViewController {
struct GlobalVariables{
static var Flat:String?
static var Flong:String?
static var Tlat:String?
static var Tlong:String?
}
override func viewDidLoad() {
super.viewDidLoad()
Flat = "flat value";
Flong="flong value";
Tlat="Tlat value";
Tlong="tlong value";
}
...
}
And you can use these variables in another view controller:
class Class2ViewController: UIViewController
{
...
print(Class1ViewController.GlobalVariables.Flat)
print(Class1ViewController.GlobalVariables.Flong)
print(Class1ViewController.GlobalVariables.Tlat)
print(Class1ViewController.GlobalVariables.Tlong)
...
}

Actually, the "viewDidLoad()" function is not called. It's will be called when you display the viewController, for example, a UINavigationController push it. In your case, you just created the viewController, not displayed it. If you want to init these variables without displaying the viewController, you need to do this:
class ViewController: UIViewController {
var Flat:String?
var Flong:String?
var Tlat:String?
var Tlong:String?
required init?(coder:NSCoder) {
super.init(coder:coder)
self.customInit()
}
override init(nibName: String?, bundle: Bundle?) {
super.init(nibName: nibName, bundle: bundle)
self.customInit()
}
func customInit() {
Flat = "flat value";
Flong="flong value";
Tlat="Tlat value";
Tlong="tlong value";
}
//.......
}

What your trying to achieve is a kind of model class. I would suggest you create a simple model class which is not subclass of UIViewcontroller like so.
class Model: NSObject {
var fLat: String?
var fLong: String?
var tLat: String?
var tLong: String?
override init() {
super.init()
fLat = "flat value"
fLong = "flong value"
tLat = "tlat value"
tLong = "tlong value";
}
// for print I have forced unwrapped so remember to check before force unwrapping smi)e
func calculation() {
print("orgin_lat new\(fLat!)")
print("origin_lng new\(fLong!)")
print("origin_lat new\(tLat!)")
print("origin_lng new \(tLong!)")
}
}
Now inside your main View controller you can initialize and call the function like so
let model = Model()
model.calculation()

Related

How to set Struct Variable data from one view controller And Getting same value from Another view controller

Im new in swift. I have create a struct class with one variable. Im trying to set value of that struct variable from my first view controller which is working perfectly but when im trying to get that same value from second view controller its give me nil value.
below is my some codding
//Struct class
import Foundation
import UIKit
struct CompanyData {
var companyName : String?
mutating func setData(name : String)
{
companyName = name
}
}
// FIRST VIEW CONTROLLER
import UIKit
class SelfCompanyNameView: UIViewController {
#IBOutlet weak var companyNameTxt: TextfieldDesign!
var company = CompanyData()
var comName = ""
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func compnyBtnPress(_ sender: Any)
{
if companyNameTxt.text?.count == 0
{
Alert.showAlert(on: self, with: "Required", message: "Please enter your company name")
}
else
{
comName = companyNameTxt.text!
company.setData(name: comName)
print("\(comName)===\(company.companyName!)")
let vc = storyboard?.instantiateViewController(withIdentifier: "SelfAddressView") as! SelfAddressView
navigationController?.pushViewController(vc, animated: true)
}
}
}
//SECOND VIEW CONTROLLER
import UIKit
class SelfAddressView: UIViewController {
var company = CompanyData()
override func viewDidLoad() {
super.viewDidLoad()
print(company.companyName)
}
}
You need to pass your model to secondView Controller like following code
// FIRST VIEW CONTROLLER
let vc = storyboard?.instantiateViewController(withIdentifier: "SelfAddressView") as! SelfAddressView
vc.company = company
navigationController?.pushViewController(vc, animated: true)
//SECOND VIEW CONTROLLER
import UIKit
class SelfAddressView: UIViewController {
var company: CompanyData!
override func viewDidLoad() {
super.viewDidLoad()
print(company.companyName)
}
}
You need to declare a static variable as a shared instance of your struct. And use that while setting and getting your value.
E.G.
struct CompanyData {
static let shared = CompanyData()
var companyName : String?
mutating func setData(name : String)
{
companyName = name
}
}
While setting the value, use as:
company.shared.setData(name: comName)
And while getting the value, use as:
print(company.shared.companyName)
I would rather use Protocols and delegators. Here is a great tutorial will help you understand the concept Sean Allen Swift Delegate Protocol Pattern Tutorial - iOS Communication Patterns Part 1

Use function from a structure in class

I am new to Swift and I have trouble using classes and structures.
I have a Structure called Workspace:
struct Workspace: Decodable {
var guid: String
var name: String
func getUserWorkspace(base: String, completed: #escaping () -> ()){
//some code
}
}
Here is my class User:
public class User {
var Wor = [Workspace]()
var WorData:Workspace? = nil
//+some other var & functions
}
So what I'm doing in my view controller is this:
class SecondViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var listView: UITableView!
var co = User()
override func viewDidLoad() {
super.viewDidLoad()
co.WorData?.getUserWorkspace(base: co.Base) {
print("success")
self.listView.reloadData()
self.updateVertically()
}
listView.delegate = self
listView.dataSource = self
}
The problem is that the code never goes inside the function co.WorData?.getUserWorkspace(base: co.Base)
Before I put it in the structure it was directly in the class but since I changed it it doesn't work anymore so I think I might be calling it the wrong way ?
WorData is nil.
Conditional unwrapping (co.WorData?.getUserWorkspace(base: co.Base) will check WorData has a value before trying to call the method. If it was nil and Swift didn't do this, it would crash.
You either need to set it as new all the time
var worData = Workspace()
Set it after class init
var user = User()
user.worData = Workspace() // or pass a specific one in
or require your User object to be initialised with a Workspace
class User: NSObject {
var wor = [Workspace]()
var workspace: Workspace // use lower camel case for var names
required init(workspace: Workspace) {
self.workspace = workspace
}
}

instantiated class is nil when called inside viewdidload()

I am trying to learn the VIPER architecture model and one thing I can't figure out is when I do the following:
Instantiate promotionPresenter class
Instantiate promotionsViewController
assign promotionsViewController.presenter = (instantiated promotionPresenter class from step 1)
try to access the instantiated presenter class from inside viewdidload() function within promotionviewController class.
presenter is nil.
Why is presenter nil? I already instantiated it.
import UIKit
/*
* The Router responsible for navigation between modules.
*/
class PromotionsWireframe : PromotionsWireframeInput {
// Reference to the ViewController (weak to avoid retain cycle).
var promotionsViewController: PromotionsViewController!
var promotionsPresenter: PromotionsPresenter!
var rootWireframe: RootWireframe!
init() {
let promotionsInteractor = PromotionsInteractor()
// Presenter is instantiated
promotionsPresenter = PromotionsPresenter()
promotionsPresenter.interactor = promotionsInteractor
promotionsPresenter.wireframe = self
promotionsInteractor.output = promotionsPresenter
}
func presentPromotionsIntefaceFromWindow(_ window: UIWindow) {
//view controller is instantiated
promotionsViewController = promotionsViewControllerFromStoryboard()
//presenter of view controller is assigned to instantiaed class
promotionsViewController.presenter = promotionsPresenter
promotionsPresenter.view = promotionsViewController
}
private func promotionsViewControllerFromStoryboard() -> PromotionsViewController {
let storyboard = UIStoryboard(name: "PromotionsStoryboard", bundle: nil )
let viewController = storyboard.instantiateViewController(withIdentifier: "promotionsViewController") as! PromotionsViewController
return viewController
}
}
import UIKit
class PromotionsViewController : UIViewController, PromotionsViewInterface {
// Reference to the Presenter's interface.
var presenter: PromotionsModuleInterface!
var promotions: [Promotion]!
/*
* Once the view is loaded, it sends a command
* to the presenter asking it to update the UI.
*/
override func viewDidLoad() {
super.viewDidLoad()
// getting error because presenter is unwrapped as nil
self.presenter.updateView()
}
func showPromotionsData(_ promotions: [Promotion]) {
// need to implement
}
}
import Foundation
class PromotionsPresenter : PromotionsModuleInterface, PromotionsInteractorOutput {
// Reference to the View (weak to avoid retain cycle).
var view: PromotionsViewInterface!
// Reference to the Interactor's interface.
var interactor: PromotionsInteractorInput!
var wireframe: PromotionsWireframe!
func updateView() {
self.interactor.fetchLocalPromotions()
}
func PromotionsFetched(_promotions: [Promotion]) {
// need to implement
}
}
I suggest you take this boilerplate (https://github.com/CheesecakeLabs/Boilerplate_iOS_VIPER) and read this post (https://www.ckl.io/blog/best-practices-viper-architecture/) in order to learn not only how to correctly initialize your VIPER modules, but also how to automate VIPER files creation and initiazlization

swift: defer non-optional object initialization

When dialing with CocoaTouch, it often happens that UIView(Controller) subclass properties can't be initialized in init method (ex. we need view already loaded), but logically they are non-optional and even non-var. In such cases the property must be optional to compile without errors, what looks pretty ugly - the code is fulfilled with !.
Is there any way to solve this problem? I would imagine some deferred initialization. Perfectly if such property can compile without initial value and crash at runtime if it's accessed prior to be initialized.
Some code sample to describe the issue:
class MyVC: UIViewController {
#IBOutlet var someLabel: UILabel!
let viewBasedParam: CustomClass // how to keep it non-optional if it can be initialized after view has been loaded?
override func viewDidLoad() {
super.viewDidLoad()
self.viewBasedParam = CustomClass(self.someLabel.text)
}
}
P.S. CustomClass can't have default initializer, because it requires data from view.
In your MyVC you can have a convenience init method where you can initialize the let variables. Try this and let me know if it works for you:
class MyVC: UIViewController {
let viewBasedParam: CustomClass
convenience init() {
self.init(nibName:nil, bundle:nil)
self.viewBasedParam = CustomClass(self.someLabel.text)//else just initialize with empty string here and then assign actual value in viewDidLoad
}
}
As far as I've discovered the workaround solution may be following:
class MyVC: UIViewController {
#IBOutlet var someLabel: UILabel!
private var _viewBasedParam: CustomClass? = nil
var viewBasedParam: CustomClass {
get { return self._viewBasedParam! } // always unwrap private optional
set { self._viewBasedParam = newValue }
}
override func viewDidLoad() {
super.viewDidLoad()
self.viewBasedParam = CustomClass(self.someLabel.text)
}
}

can't change property on parent class

I have a view controller class:
class PostImageController: UIViewController {
var textToChange:String = "original"
//Action run to change the text:
#IBAction func temp(sender: AnyObject) {
className().changeText()
println(textToChange)
}
}
The goal here, is to change "original" by "new Text" from an other file containing a class.
I tried this in the class file that is called in the view controller:
class className: PostImageController {
func changeText() {
super.textToChange = "New text"
}
}
Which does strictly nothing.
and this instead of previous exemple still in the class file:
override var textToChange: String {
return "Modified !!"
}
which I cannot even build with because of error message: "Cannot override mutable property with read-only property 'textToChange'".
The goal here, is to be able to change a property from a subclass file. If you have a clue why, please advise.
use self instead of super here
func changeText() {
self.textToChange = "New text"
}
Another solution will be to initialise textTochange in the init method of your subclass like this :
init() {
super.init()
self.textToChange = "Modified !!"
}
But the real problem here is that you print textToChange in the super class. Try this :
#IBAction func temp(sender: AnyObject) {
var subclassObject = className().changeText()
println(subclassObject.textToChange)
}

Resources