UIButton become nil when I open settings viewController - swift

I have map and zoom in/out button on it as strong outlet and settings viewController, where show/hide settings crash app because outlet button become nil. How to resolve this?
In mainViewController:
#IBOutlet var zoomIn: UIButton!
#IBOutlet var zoomOut: UIButton!
...
and
func setZoomFalse(){
zoomIn.isHidden = true
zoomOut.isHidden = true
}
func setZoomTrue(){
zoomIn.isHidden = false
zoomOut.isHidden = false
}
SettingsViewController is open with:
self.present(self.settingsViewController, animated: true, completion: nil)
from slide menu
and this call make crash in settingsViewController:
#objc func switchChanged1(_ sender : UISwitch!){
let defaults = UserDefaults.standard
defaults.set(sender.isOn, forKey: settingsView.settingsIsZoom)
isZoom = sender.isOn
if isZoom {
mainViewController.setZoomTrue()
} else {
mainViewController.setZoomFalse()
}
}

I resolve this on this way, I set global variable to true in settingsViewController, which is defined as global in maonViewController, above class definition and in viewWillApear check if this variable is true and if yes I call setZoomTrue and it works on this way, when it's called from different viewController it crashes with nil message ...

Related

Unable to access property of UITableView subclass

I am trying to test whether the method ReloadData() is called by an instance of UITableView when it's dataSource is updated.
I've created a subclass of UITableView called MockTableView. It has a bool called reloadDataGotCalled which is set to true when the overridden function reloadData() is called. I then try access that property from within my test class to test whether it is true.
However when I try to do so the compiler gives me the message that "Value of type 'UITableView' has no member 'reloadDataGotCalled'"
I'm not sure why it's doing that, because as far as I can see I've set that value to be of the type 'MockTableView' which should have that member?
// A ViewController that contains a tableView outlet that I want to test.
class ItemListViewController: UIViewController {
let itemManager = ItemManager()
#IBOutlet var tableView: UITableView!
#IBOutlet var dataProvider: (UITableViewDataSource & UITableViewDelegate & ItemManagerSettable)!
#IBAction func addItem(_ sender: UIBarButtonItem) {
if let nextViewController = storyboard?.instantiateViewController(identifier: "InputViewController") as? InputViewController {
nextViewController.itemManager = itemManager
present(nextViewController, animated: true, completion: nil)
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = dataProvider
tableView.delegate = dataProvider
dataProvider.itemManager = itemManager
}
}
// My test class
class ItemListViewControllerTest: XCTestCase {
var sut: ItemListViewController!
override func setUp() {
//Given
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(identifier: "ItemListViewController")
sut = (viewController as! ItemListViewController)
//When
sut.loadViewIfNeeded()
}
// The test where I'm trying to assign sut.tableView to mockTableView
func test_TableView_IsReloadedWhenItemAddedToItemManger() {
let mockTableView = MockTableView()
sut.tableView = mockTableView
let item = ToDoItem(title: "Foo")
sut.itemManager.add(item)
sut.beginAppearanceTransition(true, animated: true)
sut.endAppearanceTransition()
XCTAssertTrue(sut.tableView.reloadDataGotCalled) // <- this is where I'm getting the compiler message "Value of type 'UITableView' has no member 'reloadDataGotCalled'"
}
}
// My mockTableView subclass in an extension of the ItemListViewControllerTests
extension ItemListViewControllerTest {
class MockTableView: UITableView {
var reloadDataGotCalled = false
override func reloadData() {
super.reloadData()
reloadDataGotCalled = true
}
}
}
I'm expecting that it should compile, and then the test should fail because I've not written the code to make it pass yet?
You have defined tableView instance in ItemListViewController as UITableView. So, you can't access the MockTableView's property with that instance.
You can only access the parent's properties from the children not the vice versa. If you still want to access the property you can try something like the snippet below.
XCTAssertTrue((sut.tableView as! MockTableView).reloadDataGotCalled)
Hope it helps.

I want to pass UIView isHidden property from another view controller

I have a UIView set to hidden on a View Controller (product menu), then the user clicks on a product via tableview cell. When they hit return to the initial View Controller I want to make the UIView in the first VC visible.
When I use the code below I get the error: Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
{
//First View Controller
#IBOutlet weak var basketView: UIView!
.
.
self.basketView?.isHidden = true
//Second View Controller
#IBAction func returnBtn(_ sender: UIButton) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let menuCV = storyBoard.instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
menuCV.basketView.isHidden = false
self.present(menuCV, animated: true, completion: nil)
}
}
You can't access any outlet before the vc is presented/loaded as i'll be nil so
Option 1
menuCV.loadViewIfNeeded()
menuCV.basketView.isHidden = false
Option 2
Add a bool value
menuCV.hideBasket = false
Then set this inside viewDidLoad of MenuViewController
self.basketView.isHidden = hideBasket

flip card causes fatal error in swift

I am following this card flipping tutorial and instead of creating the UIView and the UIImageViews programmatically I have created these in my storyboard.
When I click the card, the animation kicks in and turns over to the front image, but when I click again, this creates a fatal error:
unexpectedly found nil while unwrapping an Optional value.
I can not figure out why this error occurs.
Here is the code which is the transformation of the above mentioned tutorial:
class FirstViewController: UIViewController {
#IBOutlet weak var flashCardView: UIView!
#IBOutlet weak var backImage: UIImageView!
#IBOutlet weak var frontImage: UIImageView!
var showingBack = true
override func viewDidLoad() {
super.viewDidLoad()
let singleTap = UITapGestureRecognizer(target: self, action: Selector("tapped"))
singleTap.numberOfTapsRequired = 1
flashCardView.addGestureRecognizer(singleTap)
flashCardView.addSubview(backImage)
view.addSubview(flashCardView)
}
func tapped() {
if (showingBack) {
UIView.transitionFromView(backImage, toView: frontImage, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromRight, completion: nil)
showingBack = false
} else {
UIView.transitionFromView(frontImage, toView: backImage, duration: 1, options: UIViewAnimationOptions.TransitionFlipFromLeft, completion: nil)
//here I get the error when flipping the card back to the back image
showingBack = true
}
}
}
I believe that when you transition, the old image's reference count is decremented, and since they're declared as weak it is getting destroyed. Try removing the weak declarations, and it will probably work. Looking at the tutorial, they don't have weak.

Having issues setting delegate with Observer Pattern

I'm trying to realize the Observer Pattern and I'm experiencing some difficulty as my delegate doesn't seem to be setting properly.
In my Main.storyboard I have a ViewController with a container view. I also have an input box where I'm capturing numbers from a number keypad.
Here's my storyboard:
I'm trying to implement my own Observer Pattern using a protocol that looks like this:
protocol PropertyObserverDelegate {
func willChangePropertyValue(newPropertyValue:Int)
func didChangePropertyValue(oldPropertyValue:Int)
}
My main ViewController.swift
class ViewController: UIViewController {
#IBOutlet weak var numberField: UITextField!
// observer placeholder to be initialized in implementing controller
var observer : PropertyObserverDelegate?
var enteredNumber: Int = 0 {
willSet(newValue) {
print("//Two: willSet \(observer)") // nil !
observer?.willChangePropertyValue(5) // hard coded value for testing
}
didSet {
print("//Three: didSet")
observer?.didChangePropertyValue(5) // hard coded value for testing
}
}
#IBAction func numbersEntered(sender: UITextField) {
guard let inputString = numberField.text else {
return
}
guard let number : Int = Int(inputString) else {
return
}
print("//One: \(number)")
self.enteredNumber = number // fires my property observer
}
}
My ObservingViewController:
class ObservingViewController: UIViewController, PropertyObserverDelegate {
// never fires!
func willChangePropertyValue(newPropertyValue: Int) {
print("//four")
print(newPropertyValue)
}
// never fires!
func didChangePropertyValue(oldPropertyValue: Int) {
print("//five")
print(oldPropertyValue)
}
override func viewDidLoad() {
super.viewDidLoad()
print("view loads")
// attempting to set my delegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
print("//six \(pvc)")
pvc.observer = self
}
}
Here's what my console prints:
What's happening
As you can see when my willSet fires, my observer is nil which indicates that I have failed to set my delegate in my ObservingViewController. I thought I set my delegate using these lines:
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let pvc = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as! ViewController
print("//six \(pvc)")
pvc.observer = self
However, I must be setting my delegate incorrectly if it's coming back nil.
Question
How do I properly set my delegate?
You are calling into the storyboard to instantiate a view controller and setting it as the observer, however that instantiates a new instance of that view controller, it doesn't mean that it is referencing the one single "view controller" that is in the storyboard. ObservingViewController needs another way to reference the ViewController that has already been created.
So #Chris did reenforce my suspicions which helped me to figure out a solution for assigning my delegate to my view controller properly.
In my ObservingViewController I just need to replace the code in my viewDidLoad with the following:
override func viewDidLoad() {
let app = UIApplication.sharedApplication().delegate as! AppDelegate
let vc = app.window?.rootViewController as! ViewController
vc.observer = self
}
Rather than creating a new instance of my view controller, I'm now getting my actual view controller.

Change ViewController based on IF statement

I need to learn how to go to a different viewcontroller based on an if statement. I'm totally new to swift. I have this already - when the counter gets to 5, I need it to go to a different view.
class ViewController: UIViewController {
#IBOutlet var countNumber: UILabel!
var conta = 0
#IBAction func counterPlus(sender: AnyObject) {
conta++
if conta == 5{
//I WANT TO GO TO A DIFFERENT VIEWCONTROLLER HERE
}else
{
countNumber.text = String(conta)
}
}
You could do this in a way of a segue, or with storyboard identifiers.
Use the following code:
// segue method, also give your segue an identifier in storyboard
if // your statement {
performSegueWithIdentifier("yourIdentifier")
}
// storyboard identifier method, give your view controller an identifier in storyboard in the "identity inspector"
if // your statement {
let destinationController = storyboard.instantiateViewControllerWithIdentifier("yourIdentifier")
presentViewController(destinationController, animated: true, completion: nil)
}
Worked with
if // your statement {
performSegueWithIdentifier("segueOne", sender: nil)
}