I want to create a custom class that extends uiviewcontroller with a function that when I create a subClass of my custom class, that function generate automatically. like viewDidLoad and didReceiveMemoryWarning in subclasses of UIViewController.
what can I do?
My CustomViewController :
class CustomViewController: UIViewController
My subclass of CustomViewController :
class MySubClass: CustomViewController {
override func generatedFunction() {
//Do something
}
}
Use code snippets.
Go to /Applications/Xcode/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates and edit the templates.
You can create a CustomViewController and then add your method to it and then call the method in the viewDidLoad. Like this
import UIKit
class CustomViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.generatedFunction()
}
public func generatedFunction() {
//Do something
}
}
Then you can use it like this,
import UIKit
class ViewController: CustomViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func generatedFunction() {
super.generatedFunction()
// Do Something
}
}
You need to make sure that if you override viewDidLoad, then you need to call super.viewDidLoad() in it.
Related
I need to post a notification on viewDidLoad of every one of my ViewControllers. I have a BaseViewController with a postNotification method, and it gets an enum as a parameter to identify the screen. It looks like this
class BaseViewController {
func postNotification(for screen: ScreenName) {
NotificationCenter.default.post(name: notification,
object: nil,
userInfo: ["ScreenName": screen])
}
}
class AViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
postNotification(for: screenA)
}
}
class BViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
postNotification(for: screenB)
}
}
Suppose we need to add another view controller later in the future, such as CViewController. I want to force the developer of CViewController to call this postNotification method with screen enum.
What is the best practice to achieve this on Swift?
Edit
Thanks to Loren's suggestion, I added a protocol on my base class
typealias BaseController = BaseViewController & BaseProtocol
protocol BaseProtocol {
var screenName: ScreenName { get }
}
This forces all my viewcontrollers to conform protocol and initialize screenName, but now I can't get it from my BaseViewController. If I can get child view controller's screenName property from BaseViewController, I would eliminate calling postNotification method on each child, and call it only on BaseViewController
class BaseViewController: UIViewController {
var screenName: ScreenName!
override func viewDidLoad() {
super.viewDidLoad()
if let screenName = self.screenName {
self.postNotification(for: screenName)
} else {
fatalError("screenName must be instantiated")
}
}
func postNotification(for screen: ScreenName) {
NotificationCenter.default.post(name: notification,
object: nil,
userInfo: ["ScreenName": screen])
}
}
class AViewController: BaseViewController {
override func viewDidLoad() {
self.screenName = screenA
super.viewDidLoad()
}
}
class BViewController: BaseViewController {
override func viewDidLoad() {
self.screenName = screenB
super.viewDidLoad()
}
}
Try this since you are using inheritance, have BaseViewController inherit UIViewController superclass, then create a screenName variable. In your childViewControllers instantiate the screenName before calling super.viewDidLoad(). You can use protocols like you mentioned to force the implementation of the variable, but it just seems like overkill for just one variable.
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.
I have a viewController with another containerView insider set up to appear temporarily (added programmatically). The containerView is a sort of operation bar, which allows you to change values of the viewController. The protocol called from an IBAction of a button however, does not call the protocol set up inside the viewController class.
Here is the code from both classes:
class viewController: UIViewController, updateListDelegate {
let dataSource = containerView()
override func viewDidLoad() {
super.viewDidLoad()
dataSource.delegate = self
}
func updateList(sender: containerView) {
print("is called") //is not printed
}
}
The code from the containerView:
protocol updateListDelegate {
func updateList(containerView)
}
class containerView: UIViewController {
var delegate: updateListDelegate?
#IBAction func AddSong(_ sender: UIButton) {
self.delegate?.updateList(sender: self)
}
}
If this method is only to be called from one object, then, in my opinion, I would not define a protocol. If multiple objects are to call this method, then I would define a protocol. This is typically how you would call a method backwards, using a basic delegate.
class ViewController: UIViewController {
let container = ContainerView()
override func viewDidLoad() {
super.viewDidLoad()
container.viewControllerDelegate = self
// push to this instance of container at some point
}
func doSomething() {
print("great success")
}
}
class ContainerView: UIViewController {
weak var viewControllerDelegate: ViewController?
#objc func someAction() {
if let viewControllerDelegate = viewControllerDelegate {
viewControllerDelegate.doSomething()
}
}
}
// prints "great success" when someAction() called
One of the most common mistakes people make is not keeping track of instances. For delegates to work, you must be sure you are using the specific instances that you've instantiated and assigned those delegates to.
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.
I have two classes. One class is named ViewController and the other class is named TabView.
My goal is to call a function changeTab() which is inside the TabView class from the ViewController.
Somehow I am having trouble with it because everytime my delegate is nil.
Here is my code for ViewController:
protocol TabViewProtocol: class {
func changeTab()
}
class ViewController: NSViewController {
// delegate
weak var delegateCustom : TabViewProtocol?
override func viewDidLoad() {
print(delegateCustom) // outputs "nil"
}
buttonClickFunction() {
print(delegateCustom) // outputs "nil"
delegateCustom?.changeTab() // doesn't work
}
}
Here is my code for TabView:
class TabView: NSTabViewController, TabViewProtocol {
let myVC = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
myVC.delegateCustom = self
}
func changeTab() {
print("test succeed")
}
}
Can someone explain me what I am doing wrong? - I am new to delegates and protocols...
You are using the delegate pattern wrongly. It is hard to tell which controller you want to define the protocol for and which one you want to adopt it - but here is one possible way.
// 1. Define your protocol in the same class file as delegate property.
protocol TabViewProtocol: class {
func changeTab()
}
// 2. Define your delegate property
class ViewController: NSViewController {
// delegate
weak var delegateCustom : TabViewProtocol?
override func viewDidLoad() {
// It should be nil as you have not set the delegate yet.
print(delegateCustom) // outputs "nil"
}
func buttonClickFunction() {
print(delegateCustom) // outputs "nil"
delegateCustom?.changeTab() // doesn't work
}
}
// 3. In the class that will use the protocol add it to the class definition statement
class TabView: NSTabViewController, TabViewProtocol {
let myVC = ViewController()
override func viewDidLoad() {
super.viewDidLoad()
myVC.delegateCustom = self
// Should output a value now
print(myVC.delegateCustom) // outputs "self"
}
func changeTab() {
print("test succeed")
}
}
you are creating a new instance in this line:
let myVC = ViewController()
you should get existing instance of your ViewController.then set
myVC.delegateCustom = self