Accessing IBOutlet from another class - ios

I am calling a class function from my ViewController class like this:
Buttons.set_cornerRadius(10)
I have another .swift file where I have the function declared:
class Buttons {
class func set_cornerRadius(radius: CGFloat) {
ViewController().someButton.layer.cornerRadius = radius
}
}
When I'm trying to run this it throws the error: "Unexpectedly found nil while unwrapping an optional Value".
I checked the Storyboard-IBOutlet connections already. Everything is connected right.
If I call the method in the same class like this, everything works:
class ViewController: UIViewController {
#IBOutlet weak var someButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
set_cornerRadius(10)
}
func set_cornerRadius(radius: CGFloat) {
someButton.layer.cornerRadius = radius
}
}
How can I fix this? What am I doing wrong/not understanding right?
Thanks in advance.

You access a generic ViewController, but need to use an existing UIView. Do something like this:
class Test: UIViewController {
class func set_cornerRadius(yourView: UIView, radius: CGFloat) {
yourView.layer.cornerRadius = radius
}
}
That way, you pass the UIView you want to set the corner-radius.

You extend your ViewController class like so:
extension ViewController {
func set_cornerRadius(radius: CGFloat) {
someButton.layer.cornerRadius = radius
}
}
Now you can call this method in your original ViewController file using: set_cornerRadius(someValue) in your viewDidLoad or wherever you want. You can put this extension in a different file.

Related

Swift - UIView Delegate Protocol not returning value

I am trying to apply the colour picker from the question below.
Simple swift color picker popover (iOS)
The way I set this up was the colour picker class is attached to a UIView within the main view controller. The code by Michael Ros works but when I try to access it using my main view controller nothing happens. Below is the code I use in my view controller. Is this correct? I went over other questions and I am not sure what I am doing wrong.
class ViewController: UIViewController {
weak var colorPickerDelegate: ColorPickerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
self.colorPickerDelegate = self
}
}
}
extension ViewController: colorPickerDelegate {
func colorChanged(color: UIColor) {
print(color)
}
}
The color picker code can be found on the attached question as I wasn't sure if it was allowed to copy the code over.
Thanks for the help
You should sublcass UIView and assign it to the view controllers view, then set the delegate of the ColorPickerView to the view controller:
ColorPickerView.swift
class ColorPickerView : UIView {
weak var delegate: ColorPickerDelegate?
// Other code from Michael Ros's adaptation.
}
ViewController.swift
import UIKit
class ViewController: UIViewController {
lazy var colorPickerView = ColorPickerView(frame: CGRect(origin: .zero, size: CGSize(width: self.view.frame.width, height: 300)))
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.colorPickerView.delegate = self
self.view.addSubview(colorPickerView)
}
}
extension ViewController: ColorPickerDelegate {
func colorDidChange(color: UIColor) {
print(color)
}
}
you should replace
colorChanged -> colorDidChange !
if you delegate is ColorPickerDelegate; I think so

Implement functionality for all the UIViewControllers using Swift

Is there a way to implement functionality for all the UIViewControllers ?
I'm trying to extend a specific behavior for all the UIViewControllers, is very standard.
For example:
MyBaseClass
class MyBaseClass {
public func load(viewController:UIViewController){
print("The size of the view is \(viewController.view.size.width)")
}
}
I have to implement a similar behavior among 100 UIViewController
One way is to use protocols in combination with an extension to UIViewController.
Define your behavior as a protocol and extend UIViewController to implement it:
protocol WidthProtocol {
func showWidth()
}
extension UIViewController: WidthProtocol {
func showWidth() {
print("The width of the view is \(self.view.frame.size.width)")
}
}
Once you have that in place, you can call your function from any subclass of UIViewController, such as:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Show the width
showWidth()
}
}
Or if you don't want to call a the same function in all your view controller you can just subclass it:
class YourCustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("The size of the view is \(view.frame.width)")
}
}
then just replace UIViewController by YourCustomViewController:
class oneOfYour100Controler : UIViewController {
to something like that:
class oneOfYour100Controler : YourCustomViewController {
Then you don't need to do anything, the message will be print automatically.

Unable to change UILabel in a method after calling different method in different class

I am trying to update a UILabel with data retrieved from a different class, so in ViewDidLoad, I am calling a method in that different class, then in that class, calling a method in the ViewController to update the UILabel. Here is a simplified version of the code I'm trying to run:
import UIKit
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
test().runTest()
}
func print() {
label.text = "test123"
}
}
and the other class:
import UIKit
class test: UIView {
func runTest() {
ViewController().print()
}
}
I keep getting an error message printed in the console saying: "fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)"
And an error on the "label.text = "test123" saying: "Thread 1: EXC_Bad_Instruction(code=EXC_(386_INVOP, subcode = 0x0)"
Thanks in advance for your help.
Your label IBOutlet is nil because you are creating a new viewcontroller instance and your viewcontroller is not attached any story board. you can pass self to func runTest() and on self you can call print. Hope it will help!
You can use this
import UIKit
class ViewController: UIViewController {
#IBOutlet var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
test().runTest(self)
}
func print() {
label.text = "test123"
}
}
import UIKit
class test: UIView {
func runTest(controller:ViewController) {
controller.print()
}
}
Your problem is that you are running the function on a new instance of your view controller rather, you should be running it on the already created instance. For instance, if your view is a child of your view controller you can do this, in your class test replace edit your function test to be this.
func runTest() {
if let vc = self.parent as? ViewController{
vc.print()
}
}
This should run the function on the already created instance of your view controller.

How to call a function that is located in another class in Swift?

I try to make the Label in iOS app to show "asdf" in label using 2 view controller.
I try to run testA() function but it shows out an error: ViewController.swift:15:9: Use of unresolved identifier 'testA'
My initial code:
ViewController.swift
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
testA()
}
}
In another controller (TestViewController):
import UIKit
class TestViewController: UIViewController {
#IBOutlet weak var testLabel: UILabel!
func testA() {
testLabel.text = "asdf"
}
}
and my Main.storyboard is linked to TestViewController class
I did a little bit search on google and I came to try out inheritance and It did not shows the error, but the function was not called.
I try to use Inheritance method:
In View Controller (ViewController.swift):
import UIKit
class ViewController: TestViewController {
override func viewDidLoad() {
super.viewDidLoad()
testA()
}
}
The error was resolved, but the label did not change to asdf
How do I make my ViewController.swift able to call the function testA() that is located in another controller TestViewController.swift ?
You can create an object of that class and you can call the function as below.
let testVC = TestViewController()
Now call the function using the object
testVC.testA()
Or better approach is to create a class func if you want to call it from many places and it's independent of the object.
class Helper {
class func testFunction() {
// Do something
}
}
In above scenario, you don't have to create the object as it's a class method so call it like below.
Helper.testFunction()
You can use NSNotification or ou can use delegate if load the second view after the first.
public the testA() function and call the
TestViewController.testA()
in the override func viewDidLoad()of ViewController
import TestViewController at first.

Cannot pass immutable value of type 'NSObject' as inout argument

This should work, but I've got no clue why it doesn't. The code is self-explanatory.
class Themer {
class func applyTheme(_ object: inout NSObject) {
//do theming
}
}
And I apply theme to the button like so:
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
Themer.applyTheme(&button)
}
The button object is a variable, yet the compiler throws an error.
Since button is an object, this syntax
Themer.applyTheme(&button)
means that you want to change the reference to that object. But this is not what you want. You want to change the referenced object so you simply need to write
Themer.applyTheme(button)
Finally you also don't need the inout annotation
class Themer {
class func applyTheme(_ object: AnyObject) {
//do theming
}
}
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
Themer.applyTheme(self.button)
}
}
But...
However, what should your applyTheme method do? It receives AnyObject and then what? You could make it a little but more specific and use a UIView as param
class Themer {
class func applyTheme(view: UIView) {
//do theming
}
}
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
Themer.applyTheme(view: button)
}
}
Now you have a chance to write meaningful code inside Themer.applyTheme.
inout is for the case that you want to change the reference, that is replace one object with another object. That's a very, very, very bad thing to do with an IBOutlet. That button is used in a view, connected up to lots of things, and if you change the variable, all hell will break lose.
Apart from that, listen to appzYourLife.

Resources