Accessing variables from another ViewController in Swift - ios

I have the following ViewController:
class PageContentViewController: UIViewController {
var pageIndex: Int
}
How would I access pageIndex from another ViewController?
I need to access pageIndex in this function:
func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {
//var index: Int
//index = ?
NSUInteger index = ((PageContentViewController*) viewController).pageIndex; // in Swift?
if ((index == 0) || (index == NSNotFound)) {
return nil;
}
index--;
return [self viewControllerAtIndex:index]; // in Swift?
}

Everything by default in swift is public, and thus if you declare something like this:
class SomeViewController: UIViewController {
var someVariable: SomeType = someValue
init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
}
You can access it as long as you have an instance of it:
var myCustomViewController: SomeViewController = SomeViewController(nibName: nil, bundle: nil)
var getThatValue = myCustomViewController.someVariable

ViewController1.swift
class ViewController1: UIViewController {
struct GlobalVariable{
static var myString = String()
}
}
ViewController2.swift
class ViewController2: UIViewController
{
print(ViewController1.GlobalVariable.myString)
}

I solved this way . .
class StaticLinker
{
static var viewController : PageContentViewController? = nil
}
class PageContentViewController: UIViewController
{
var pageIndex: Int
StaticLinker.viewController = self
}
class AnotherClass
{
StaticLinker.viewController.pageIndex = 100
}

Here's my attempt to convert that code to swift:
func pageViewController(pageViewController: UIPageViewController!, viewControllerBeforeViewController viewController: UIViewController!) -> UIViewController! {
var pageController = viewController as PageContentViewController
var index: Int? = pageController.pageIndex
if var idx: Int = index{
if idx == 0{
return nil
}
else{
idx--
return viewControllerAtIndex(idx)
}
}
else{
return nil
}
}
class PageContentViewController: UIViewController {
var pageIndex: Int?
}

I was facing the same problem when i have to use token in every other class, the solution is pretty simple, What i did was
var access = LoginViewController()
token = access.token
but the problem it encountered was: Using the default value for token.
so i made that variable static and used this in view did load.
var token : String = ""
var access = LoginViewController.self
token = access.token

class color: UIViewController {
var blue:Int = 90
}
access it from other class (make sure to call the variable within a function otherwise you gonna get error )
class ViewController: UIViewController{
var example:color = color()
override func viewDidLoad() {
super.viewDidLoad()
// call it here
print(example.blue)
}
}

class firstViewController: UIViewController{
var variableName: variableType = variableValue
}
You can access this variable in the secondViewController by creating an instance of firstViewController()
class secondViewController: UIViewController{
var newVariableName = firstViewController()
}
later on use the newVariableName to access the value of the variableName
newVariableName.variableName

Related

Changing Label text on main controller after modal closed swift macOS

I am using delegates to get a string value from my modal. When the modal closes I am trying to update Label text using that string. However, I am getting error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. I am not sure how to fix this. I think it's happening because the view is not yet active.
import Cocoa
class ViewControllerA: NSViewController, SomeDelegate {
#IBOutlet weak var msgLabel: NSTextField!
var s: String = "";
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
func setDetails(s: String) {
self.user = s;
print("Notified", self.s) // <-- prints: Notified hello again
msgLabel.stringValue = self.s <-- DOESN'T WORK
}
func showModal() -> Void {
msgLabel.stringValue = "hello" // <--- WORKS
let cbvc: NSViewController = {
return self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! NSViewController
}()
self.presentAsModalWindow(cbvc);
}
#IBAction func onBtn(_ sender: Any) {
self.showModal();
}
}
protocol SomeDelegate {
func setDetails(s: String)
}
class ViewControllerB: NSViewController {
#IBOutlet weak var textF: NSTextField!
var delegate: SomeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
let vc = ViewControllerA()
self.delegate = vc
}
#IBAction func onBtn(_ sender: Any) {
DispatchQueue.main.async {
self.delegate?.setDetails(s: self.textF.stringValue)
self.dismiss("ControllerAVC")
}
}
}
You have a number of problems.
In ViewControllerB.viewDidLoad you are assigning a new instance of ViewControllerA to the delegate property. Don't do that. Your viewDidLoad method should look like this:
override func viewDidLoad() {
super.viewDidLoad()
}
In the showModal method ViewControllerA should assign itself as the delegate on ViewControllerB before ViewControllerB it is presented.
func showModal() -> Void {
let cbvc: NSViewController = {
let vc = self.storyboard!.instantiateController(withIdentifier: "ControllerBVC")
as! ViewControllerB
vc.delegate = self
return vc
}()
self.presentAsModalWindow(cbvc);
}
In the setDetails method just assign the string to your text field directly:
func setDetails(s: String) {
msgLabel.stringValue = s
}

How to pass controller as an inout parameter?

I simply have such protocols:
protocol Containerable {
var containerView: UIView { get }
var containerController: UIViewController { get }
var oldViewController: UIViewController? { get set }
}
protocol ContainerRoutable: class {
func load(controller: UIViewController, into context: inout Containerable)
}
extension ContainerRoutable {
func load(controller: UIViewController, into context: inout Containerable) {
context.oldViewController?.willMove(toParent: nil)
context.oldViewController?.view.removeFromSuperview()
context.oldViewController?.removeFromParent()
controller.view.frame = context.containerView.bounds
context.containerController.addChild(controller)
context.containerView.addSubview(controller.view)
context.oldViewController = controller
controller.didMove(toParent: context.containerController)
}
func loadDashboard(into context: inout Containerable) {
let controller = assembler.resolve(DashboardViewController.self)!
load(controller: controller, into: &context)
}
}
and now on the tap action I need to use it:
mainView.dashboardButton.rx.tap.bind { [weak self] in
self?.mainView.activateDashboardMenuItem()
if var a = self as? Containerable { //warning: Conditional downcast from 'TabBarController?' to 'Containerable' is equivalent to an implicit conversion to an optional 'Containerable'
self?.router.loadDashboard(into: &a)
}
}.disposed(by: bag)
What is self?
class TabBarController: UIViewController, Containerable {
private let mainView: TabBarView
let router: TabBarRoutable
private let bag = DisposeBag()
var oldViewController: UIViewController?
var containerController: UIViewController {
return self
}
var containerView: UIView {
return mainView.containerView
}
}
How to remove the following warning?
Conditional downcast from 'TabBarController?' to 'Containerable' is equivalent to an implicit conversion to an optional 'Containerable'
Update the if-condition as,
if var a: Containerable = self {
self?.router.loadDashboard(into: &a)
}

Type checking with generics and raw types?

I have a class
class SomeViewController<T: SomeViewModel>: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource { ... }
And another class:
class AnotherViewController: UIViewController {
private weak var someVC: UIViewController?
...
func someFunc() {
if someVC is SomeViewController { ... } // attempt 1
// or
if let vc = someVC as? SomeViewController { ... } // attempt 1
...
}
...
}
I need to see if someVC is a SomeViewController so that I can access an instance variable that has nothing to do with the generic type. However, when doing a check via either attempt 1 or attempt 2, the check always fails and my inner code never executes. How do I see if it is of a type, but not specific generic type e.g. I don't have to put the type of SomeViewModel?
EDIT: Added more code for clarity.
This doesn't work because Swift wants to know the type of the generic. If you just want to access a property without dealing with the generic, you can extract that to a protocol.
protocol SomethingThatHasFoo {
var foo: String { get }
}
class SomeViewController<T>: UIViewController, SomethingThatHasFoo {
let foo = "foo"
}
class AnotherViewController {
private weak var someVC: UIViewController?
func someFunc() {
if let vc = someVC as? SomethingThatHasFoo {
print(vc.foo)
}
}
}
Here is an example that works:
class SomeViewModel{}
class A: SomeViewModel{}
class SomeViewController<T: SomeViewModel> : UIViewController{}
class AnotherViewController {
private weak var someVC: UIViewController?
init(vc: SomeViewController<A>) {
someVC = vc
}
func someFunc() {
if someVC is SomeViewController<A> {
print("\(String(describing: someVC))")
}
if let vc = someVC as? SomeViewController<A> {
print("\(vc)")
}
}
Then you have to initialize it like this:
let someVC = SomeViewController<A>()
let anotherVC = AnotherViewController.init(vc: someVC)
anotherVC.someFunc()
Hope that answered your question

self.name.text value change from another view controller gives fatal error:

I have viewcontroller and subviewcontroller I want to change self.name.text from subViewController changeIt function , to inside viewcontroller gives me
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
How can I resolve it , my codes under below.
subViewController
import UIKit
import CoreData
class subViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if prefs.string(forKey: "session") == "yes" {
let newname = prefs.string(forKey: "name")
ViewController().changeIt(name : newname)
}else{
}
}
}
ViewController
import UIKit
import CoreData
class ViewController: UIViewController {
#IBOutlet weak var name: UITextField!
class func sharedInstance() -> ViewController {
struct Singleton {
static var sharedInstance = ViewController()
}
return Singleton.sharedInstance
}
override func viewDidLoad() {
super.viewDidLoad()
}
public function changeIt(name : String){
print("New Name \(name)") /// WORKS!!
self.name.text = "\(name)" /// GIVES FATAL ERROR
}
}
(*ViewController also inside ContainerView)
you cannot set the IBOutlet directly from another controller instead declare a variable var tempName set that in your previous controller and use this variable to set your textfield self.name.text = tempName Hope this helps you

Get values of variables defined by protocol from any VC

protocol(myProtocol):-
protocol myProtocol {
var type:String { get set }
var sub:String { get }
var msg:String? { get set }
}
Class(myVC):-
class myVC: UIViewController, myProtocol {
//Protocol Declarations
var sub = myTypes.type.rawValue
var type = myTypes.type.getType()
var msg :String?
.... }
Extension:-
extension UIViewController
{
func getData() {
if self is myProtocol {
let msg = self.msg
} }
}
Getting error at 'self.msg' saying Value of type UIViewController has no member 'sub'
How do i go about it?
Any help is appreciated.
All you need to do is write another line of code in your extension class. I just tested it in my end and it worked for me. Here is the code I wrote -
extension UIViewController
{
func getData() {
if self is myProtocol {
let x = self as! myProtocol
let msg = x.msg
print(x.msg)
}
}
}
According to your example, you need to change your extension definition
extension UIViewController
as
extension myVC

Resources