Question about delegate and protocol in swift (with example) - ios

I am trying to work with delegate and protocol but met a problem.
I created 2 buttons on one ViewController and created 1 imageView in another ShowViewController. The color of the imageView will change according to which button is pressed.
ViewController.swift
import UIKit
protocol getColorProtocol {
func getColor(color:String?)
}
class ViewController: UIViewController {
var color: String?
var delegate:getColorProtocol?
#IBAction func blueButtonPressed(_ sender: Any) {
color = "blue"
delegate?.getColor(color: color)
}
#IBAction func redButtonPressed(_ sender: Any) {
color = "red"
delegate?.getColor(color: color)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
ShowViewController.swift
import UIKit
class ShowViewController: UIViewController, getColorProtocol {
var viewOne = ViewController()
#IBOutlet weak var colorView: UIImageView!
func getColor(color: String?) {
print("color is \(color!)")
if color == "red"{
colorView.backgroundColor = UIColor(displayP3Red: 255/255, green: 0/255, blue: 0/255, alpha: 1)
}
else if color == "blue" {
colorView.backgroundColor = UIColor(displayP3Red: 0/255, green: 0/255, blue: 255/255, alpha: 1)
}
}
override func viewDidLoad() {
super.viewDidLoad()
viewOne.delegate = self
}
}
press here to view the storyboard!
You may check my storyboard above.
Currently, it has no error but it cannot call the getColor function. I am wondering if the problem is coming from the delegate?.getColor(color: color) statement.
Any ideas?

First of all, in your case, you don't need to use delegate pattern
Your ViewController connect directly to ShowViewController through segue
You can use prepareForSegue instead
Secondly, I don't think you understand how delegate pattern works,
Inside ShowViewController, you're create a new ViewController called viewOne, it isn't the original ViewController so that's why your code doesn't work as expected
As I mentioned above, you should use segue
first, go to the storyboard setup your segue identifier. Then, inside your ViewController
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if (segue.identifier == "goToShowVC") {
//your code here
}
}

You don't need a delegate for this, but just prepare for segue. I see that you have two segues set up already, so in your viewcontroller, assuming your segues are called "blue" and "red" in your storyboard, you could add:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ShowViewController {
if segue.identifier == "blue" {
destinationVC.color = UIColor.blue
} else if segue.identifier == “red” {
destinationVC.color = UIColor.red
}
}
}
then you would want to add a color variable to manipulate in your showviewcontroller. For example:
var color = UIColor.white
colorview.backgroundcolor = color

Related

delegate method not getting called with UITabBarController

In FourthViewController, I have a slider, which has values ranging from 1 to 1000. The value that is set gets sent via the delegate to PatternViewController, where it should be used to do sth (I put the print for testing purposes).
I've worked with delegates before and it was all ok, checked the code multiple times and multiple answers here on stack, I can't seem to find the issue. Any help would be much appreciated
update: I have added a button so that it would be easier to track along. It turns out that by pressing first time the button, nothing happens. but if I first checkout the PatternViewController, then I go back to FourthViewController and press the button, the delegate gets triggered. anyone got any idea on why is this happening?
FourthViewController
import UIKit
class FourthViewController: UIViewController {
//MARK: Outlets
#IBOutlet var persistenceButton: UIButton!
#IBOutlet var persistenceSlider: UISlider!
#IBOutlet var persistenceLabel: UILabel!
weak var delegate: FourthViewControllerDelegate?
//MARK: Stored Properties - Constants
let userDefaults = UserDefaults.standard
let keyName = "sliderValue"
//MARK: Initializer
override func viewDidLoad() {
super.viewDidLoad()
loadSliderValue()
initialSetUp()
}
//MARK: Actions
#IBAction func handleValueChanged(_ sender: UISlider) {
updateLabel()
persistSliderValue(value: persistenceSlider.value, key: keyName)
}
//MARK: Methods
func updateLabel() {
persistenceLabel.text = String(format: "%.2f", persistenceSlider.value)
}
func persistSliderValue(value: Float, key: String) {
userDefaults.set(value, forKey: key)
}
func loadSliderValue() {
let persistedValue = userDefaults.float(forKey: keyName)
persistenceSlider.value = persistedValue
updateLabel()
}
}
func initialSetUp() {
persistenceButton.addTarget(self, action: #selector(handleButtonPressed), for: .touchUpInside)
}
#objc func handleButtonPressed() {
delegate?.valueChanged(value: persistenceSlider.value)
}
}
PatternViewController
import UIKit
class PatternViewController: UIViewController, FourthViewControllerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setUp()
}
func setUp() {
if let tabBar = self.tabBarController, let viewController = tabBar.viewControllers, let fourthViewController = viewController[3] as? FourthViewController {
fourthViewController.delegate = self
}
}
func valueChanged(value: Float) {
print(value)
}
}
It depends upon how you instantiated the tab view controller. If you do it with storyboards, for example, the view controllers for the respective tabs are instantiated lazily, only instantiated as the user taps on them. (This helps reduce latency resulting from instantiating all four of the tabs’ view controllers.)
While you theoretically could go ahead and have the tab bar controller instantiate the four view controllers programmatically up front, rather than just-in-time via the storyboard, I might instead consider specifying a UITabBarControllerDelegate for the tab bar controller. Have the tab bar controller’s delegate method update the relevant tab’s view controller’s model.
Here is an example with two tabs, the first has a slider and the second has a label that displays the slider’s value. In this simplified example, I’ve moved the model object (the value associated with the slider) into the tab bar controller, and it passes it to the second view controller when you select the associated tab.
// TabViewController.swift
import UIKit
class TabBarController: UITabBarController {
var value: Float = 0.5
override func viewDidLoad() {
super.viewDidLoad()
delegate = self
}
}
// MARK: - UITabBarControllerDelegate
extension TabViewController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
guard let viewController = viewController as? SecondViewController else { return }
viewController.value = value
}
}
And
// FirstViewController.swift
import UIKit
class FirstViewController: UIViewController {
#IBOutlet weak var slider: UISlider!
override func viewDidLoad() {
super.viewDidLoad()
guard let tabBarController = tabBarController as? TabViewController else { return }
slider.value = tabBarController.value
}
#IBAction func didAdjustSlider(_ sender: UISlider) {
guard let tabBarController = tabBarController as? TabViewController else { return }
tabBarController.value = sender.value
}
}
And
// SecondViewController.swift
import UIKit
class SecondViewController: UIViewController {
#IBOutlet weak var label: UILabel!
var value: Float = 0 { didSet { updateLabel() } }
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .percent
return formatter
}()
override func viewDidLoad() {
super.viewDidLoad()
updateLabel()
}
func updateLabel() {
label?.text = formatter.string(for: value)
}
}
Probably needless to say, I not only set the base view controller class for the two tab’s view controllers, but also set the base class for the tab bar controller’s storyboard scene to the above TabBarController.

Change the toolbar color

It is working for navigationBar:
var colour = UIColor.red
self.navigationController?.navigationBar.tintColor = colour
But do not work for toolbar:
self.navigationController?.toolbar.tintColor = colour
I searched the internet and stack overflow. No answer is workable for me.
Some people said:
self.toolbar.barTintColor = UIColor.redColor()
It is also not working for me. (value of type 'thisView' has no member 'toolbar')
I want to edit the toolbar color in coding. No change in the storyboard setting. Thanks.
EDIT:
I am working on adding a toolbar under the webview. Like go back, stop, reload.
//
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var webView: UIWebView!
var colour = UIColor.red
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.tintColor = colour
// problem in here ..........................
self.navigationController?.toolbar.tintColor = UIColor.black
let URL = NSURL(string: "https://www.apple.com")
webView.loadRequest(NSURLRequest(url: URL! as URL) as URLRequest)
}
#IBAction func backButton(_ sender: AnyObject) {
webView.goBack()
}
#IBAction func nextButton(_ sender: AnyObject) {
webView.goForward()
}
#IBAction func refreshButton(_ sender: AnyObject) {
webView.reload()
}
#IBAction func stopbutton(_ sender: AnyObject) {
webView.stopLoading()
}
}
If you've just got a toolbar that is on a ViewController in Your Storyboard all you need to do is add an IBOutlet to your View Controller and connect the toolbar in the storyboard to that outlet. This code goes in your ViewController
#IBOutlet var toolbar: UIToolbar?
Then, in the storyboard, hold the control button and click drag from View Controller (in the left sidebar) to your toolbar. This will create a connection between the toolbar in the storyboard to the toolbar var in your code. After that connection is made all you need to do is set the barTintColor on that toolbar variable like so:
self.toolbar.barTintColor = UIColor.blue
I wrote this function a few days ago to kinda workaround the fact that you can't change the color.
func setStatusBarColor(){
let view = UIView(frame: CGRect(x: 0.0, y: 0.0, width: UIScreen.main.bounds.size.width, height: 20.0))
view.backgroundColor = UIColor(red: 81/255, green: 184/255, blue: 222/255, alpha: 1)
self.view.addSubview(view)
}
Also make sure to set the statusbar to .lightContent
UIApplication.sharedApplication().statusBarStyle = .LightContent

Programatically add view behind status bar - swift

I am having a problem showing the StatusBar in my UITableViewController because it does not have a background. So I want to be able to do that programatically. I have seen this in apps like Facebook and Youtube. Can anyone help me with that?
In order to add a view behind status bar, you can use below code which is written for Swift 3
You need to create an extension for it and you can use this in any view controller where it is required.
let SCREEN_WIDTH = UIScreen.main.bounds.size.width
extension UIViewController {
func addStatusBarBackgroundView(viewController: UIViewController) -> Void {
let rect = CGRect(origin: CGPoint(x: 0, y: 0), size:CGSize(width: SCREEN_WIDTH, height:20))
let view : UIView = UIView.init(frame: rect)
view.backgroundColor = UIColor.init(red: 255/255, green: 255/255, blue: 255/255, alpha: 1) //Replace value with your required background color
viewController.view?.addSubview(view)
}
}
and simply call this by writing one line in your view controller:
override func viewDidLoad() {
super.viewDidLoad()
addStatusBarBackgroundView(viewController: self)
//Your extra code
}
Happy Coding..!!
To let your UINavigationBar stretch behind you status bar, you can implement the function position(for:) on the navigation bar's delegate.
Swift3 Example
class MyViewController: UIViewController {
#IBOutlet weak var navigationBar: UINavigationBar!
override func viewDidLoad() {
super.viewDidLoad()
navigationBar.delegate = self
}
}
extension MyViewController: UINavigationBarDelegate {
func position(for bar: UIBarPositioning) -> UIBarPosition {
return .topAttached
}
}

Delegation between two ViewControllers without segues

I am learning the concept of delegation and I am stuck in my project. I believe the solution is simple, but as this is something new for me I have no idea what is wrong.
Project concept is simple:
There are two views in the application. In the first view you press the button "change the color" and as a result second view appears. In the second view there are three text fields where user puts numbers respectively for R G and B values in RGB color. When the button is tapped, second view disappears and the first view's background should be changed with color based on the user's input. I assume that the user put correct numbers, therefore at this moment I use forced unwrapping for those values.
At this moment views appear correctly, but the background color of the first view does not change and I have no idea why.
Beneath is the code for two view controllers. I will appreciate any hints.
First VC: ViewController.swift
class ViewController: UIViewController, ColorChangeDelegate {
let secondStoryboard = UIStoryboard(name: "Second", bundle: nil).instantiateViewControllerWithIdentifier("SecondViewController") as UIViewController
var secondVC = SecondViewController()
#IBAction func changeColourButtonTapped(sender: UIButton) {
presentViewController(secondStoryboard, animated: true, completion: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
secondVC.colorDelegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func didChangeColor(controller: SecondViewController, color: UIColor) {
self.view.backgroundColor = color
}
}
and second VC: SecondViewController.swift
protocol ColorChangeDelegate {
func didChangeColor(controller: SecondViewController, color: UIColor)
}
class SecondViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var myRTextField: UITextField!
#IBOutlet weak var myGTextField: UITextField!
#IBOutlet weak var myBTextField: UITextField!
var colorDelegate : ColorChangeDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
myRTextField.delegate = self
myGTextField.delegate = self
myBTextField.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func textFieldDidBeginEditing(textField: UITextField) {
textField.becomeFirstResponder()
}
#IBAction func goButtonTapped(sender: UIButton) {
let r = Int(myRTextField.text!)!
let g = Int(myGTextField.text!)!
let b = Int(myBTextField.text!)!
let color = UIColor(red: CGFloat(r), green: CGFloat(g), blue: CGFloat(b), alpha: 1.0)
self.view.endEditing(true)
colorDelegate?.didChangeColor(self, color: color)
presentingViewController?.dismissViewControllerAnimated(true, completion: nil)
}
}
You are assigning your delegate to secondVC but the view controller that is actually being presented is in secondStoryboard, so you should set the colorDelegate property of secondStoryboard.

Change Background Color of ViewController Swift? (Single View Application)

I am making a very simple single view application in Swift (XCode 6.2) that comprises of 2 buttons "blackButton" and "whiteButton". Upon clicking blackButton it changes the View's background color to Black and upon clicking the whiteButton it changes the background to white. Can anyone suggest any possible ways to do this?
ViewController.swift:
//beginning
import UIKit
class ViewController: UIViewController {
#IBAction func blackButton(sender: AnyObject) {
}
#IBAction func whiteButton(sender: AnyObject) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
A view controller's view can be accessed through it's view property, which is just a regular UIView. UIView's have a backgroundColor property, which is a UIColor and controls the color of the view.
#IBAction func blackButton(sender: AnyObject) {
view.backgroundColor = .black
}
#IBAction func whiteButton(sender: AnyObject) {
view.backgroundColor = .white
}
For Custom Colors
#IBAction func blackButton(sender: AnyObject) {
let blackColor = UIColor(red: 255/255.0, green: 255/255.0, blue: 255/255.0, alpha: 1.0)
view.backgroundColor = blackColor
}
#IBAction func whiteButton(sender: AnyObject) {
let whiteColor = UIColor(red: 0/255.0, green: 0/255.0, blue: 0/255.0, alpha: 1.0)
view.backgroundColor = whiteColor
}
You can also use Color Literal. Easily to customize your own colors.
#IBAction func blackButton(sender: AnyObject) {
view.backgroundColor = ColorLiteral //Custom color
}
#IBAction func whiteButton(sender: AnyObject) {
view.backgroundColor = ColorLiteral //Custom color
}

Resources