View controller's data changes on 2nd attempt - ios

Hey my code changes data in another view controller on 2nd attempt on 1st just showing default values
Code inside button
#IBAction func check(_ sender: Any) {
makeRequest()
let fin = UIStoryboard(name: "FinalViewController", bundle: nil)
let pop = fin.instantiateInitialViewController()! as! FinalViewController
pop.img = icon
pop.state = state
pop.fail = failed
self.present(pop, animated: true)
}
Code inside 2nd view controller
class FinalViewController: UIViewController {
#IBOutlet weak var weathure_icon: UIImageView!
#IBOutlet weak var status: UILabel!
var fail = false
var img = ""
var state = ""
override func viewDidLoad() {
if fail == false{
super.viewDidLoad()
status.text = state
weathure_icon.image = UIImage(named: img+".png")
}
}

Please check three things in your code inside the button action.
Please cross-check, is makeRequest() asynchronous request??
is icon, state and failed parameters request coming from makeRequest() method, in this case you need to handle request data on main thread.
Please replace following in your code:
This
let fin = UIStoryboard(name: "FinalViewController", bundle: nil)
let pop = fin.instantiateInitialViewController()! as! FinalViewController
With
let fin = UIStoryboard(name: "STORYBOARD_NAME", bundle: nil)
let pop = fin.instantiateInitialViewController(identifier: "FinalViewController")! as! FinalViewController
Hope this will help you and make success with your implementation :)

Related

View Controller not loading via instantiateViewController function even with correct identifier

Goal: In a separate storyboard that is loaded via a storyboard reference in the main.storyboard, in a pageViewController acting as the initial view controller, I want to initialize an array object of viewControllers via the function .instantiateViewController(identifier:).
Issue: The last viewController I'm trying to instantiate as a constant is not loading. The error - *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load the scene view controller for identifier 'FinalVC''"
All other viewControllers in this storyboard load fine. This last view controller has a correct custom class linked and a unique storyboard identifier.
Debugging: I've created a breakpoint where this view controller is instantiated and noticed in the debugging console all other view controller objects load as "BillyCues.repeatViewController + unique identification number" while this last vc loads as "UIViewController + 0x000000000000000". It's almost as if this vc is not a part of the app bundle or referenced correctly but it's there when I search in the directory.
Debugging console screen
Things I've tried that did not work:
Check to see if another vc has the same identifier
Clean the build folder
Check "Use Storyboard ID" in the identity inspector
let finalVC = storyBoard.instantiateViewController(identifier: "FinalVC") as! FinalViewController
Restart Xcode
Create a brand new view controller with a different storyboard identifier using the same custom class
Removed all connections from buttons and labels in the last vc
Made sure all storyboard references in main.storyboard has the correct storyboard linked
Conclusion: All my googling has led to other developers encountering the error about NIBs or tableviews not necessarily a view controller. If my vc has a correct custom class and unique identifier the error should not occur. If anyone can offer guidance I'd appreciate it; I'm dumbfounded.
I hope I've asked for help in an appropriate structure but please let me know if more code or screenshots are needed.
PageViewController Code
import UIKit
class LauncherViewController: UIPageViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.setViewControllers([viewControllerList[0]], direction: .forward, animated: false, completion: nil)
// Do any additional setup after loading the view.
}
private var viewControllerList: [UIViewController] = {
let storyBoard = UIStoryboard.cueCreation
let firstVC = storyBoard.instantiateViewController(identifier: "CueNameVC")
let secondVC = storyBoard.instantiateViewController(identifier: "DueDateVC")
let thirdVC = storyBoard.instantiateViewController(identifier: "IconVC")
let fourthVC = storyBoard.instantiateViewController(identifier: "IconColorVC")
let fifthVC = storyBoard.instantiateViewController(identifier: "RepeatVC")
let finalVC = storyBoard.instantiateViewController(identifier: "FinalVC") as! FinalViewController
return [firstVC, secondVC, thirdVC, fourthVC, fifthVC, finalVC]
}()
var selectedReminderBill: CueObject?
public var currentIndex = 0
static var cueName: String = ""
static var cueDate: Date = Date()
static var cueIcon: Data = Data()
static var iconColor:String = "14CC7F"
static var repeatMonthly: Bool = false
// Navigation button functions below to move to the next or previous page
func pushNext() {
if currentIndex + 1 < viewControllerList.count {
self.setViewControllers([self.viewControllerList[self.currentIndex + 1]], direction: .forward, animated: true, completion: nil)
currentIndex += 1
}
}
func pullBack() {
print(currentIndex)
if currentIndex - 1 < viewControllerList.count {
self.setViewControllers([self.viewControllerList[self.currentIndex-1]], direction: .reverse, animated: true, completion: nil)
currentIndex -= 1
}
}
}
FinalViewController Code
import UIKit
import UserNotifications
import RealmSwift
class FinalViewController: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
cueName.text = LauncherViewController.cueName
dueDate.text = CueLogic.convertPaymentDateToString(for: LauncherViewController.cueDate)
iconBackgroundView.backgroundColor = colorLogic.colorWithHexString(hexString: LauncherViewController.iconColor)
cueIcon.image = UIImage(data: LauncherViewController.cueIcon)
repeatsMonthly.text = repeatMonthlyToString
}
override func viewDidLoad() {
super.viewDidLoad()
cueName.layer.cornerRadius = 15
cueName.clipsToBounds = true
iconBackgroundView.layer.cornerRadius = 20
iconBackgroundView.clipsToBounds = true
dueDate.layer.cornerRadius = 15
dueDate.clipsToBounds = true
repeatsMonthly.layer.cornerRadius = 15
repeatsMonthly.clipsToBounds = true
backButton.layer.cornerRadius = 15
backButton.clipsToBounds = true
saveButton.layer.cornerRadius = 15
saveButton.clipsToBounds = true
// Do any additional setup after loading the view.
}
let colorLogic = ColorLogic()
let realm = try! Realm()
weak var delegate: HomeScreenDelegate?
var launcher = LauncherViewController()
var repeatMonthlyToString: String {
get {
if LauncherViewController.repeatMonthly == true {
return "Repeats Monthly: Yes"
} else {
return "Repeats Monthly: No"
}
}
}
#IBOutlet var cueName: UILabel!
#IBOutlet var dueDate: UILabel!
#IBOutlet var saveButton: UIButton!
#IBOutlet var backButton: UIButton!
#IBOutlet var iconBackgroundView: UIView!
#IBOutlet var cueIcon: UIImageView!
#IBOutlet var repeatsMonthly: UILabel!
#IBAction func dismissButtonTapped(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
#IBAction func backButtonTapped(_ sender: Any) {
if let pageController = parent as? LauncherViewController {
pageController.pullBack()
}
}
#IBAction func saveButtonTapped(_ sender: Any) {
// Request authorization from the user to allow notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound], completionHandler: {success, error in
if success {
// schedule test
} else if let error = error {
print("error occured \(error)")
}
})
let newCue = CueObject()
let launcherVC = LauncherViewController.self
newCue.name = launcherVC.cueName
newCue.paymentDate = launcherVC.cueDate
newCue.icon = launcherVC.cueIcon
newCue.iconColor = launcherVC.iconColor
newCue.repeatsMonthly = launcherVC.repeatMonthly
NotificationLogic.scheduleLocalAlertForBill(named: newCue.name, due: newCue.paymentDate, repeatsMonthly: newCue.repeatsMonthly)
saveToDB(for: newCue)
delegate?.loadCuesFromRealm()
self.dismiss(animated: true, completion: nil)
}
func saveToDB(for cue: CueObject) {
do {
try realm.write({
realm.add(cue)
})
} catch {
print("Error - \(error)")
}
}
}
protocol HomeScreenDelegate: AnyObject {
func loadCuesFromRealm()
}
Extension I wrote in another viewController
extension UIStoryboard {
static let onboarding = UIStoryboard(name: "Onboarding", bundle: nil)
static let main = UIStoryboard(name: "Main", bundle: nil)
static let cueCreation = UIStoryboard(name:"CueCreation", bundle: nil)
}
Identity Inspector
Main Storyboard References
I'd do a few things as part of cleanup to start debugging the actual issue. In the storyboard extension, I'd rather use a static function to reference the view controller.
extension UIStoryboard {
class func createFinalVC() -> FinalViewController? {
return UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "FinalVC") as? FinalViewController)
}
}
And for implementing it, I'd use in the view controller presenting FinalViewController:
private func createCreateFinalVC() -> FinalViewController? {
return UIStoryboard.createFinalVC()
}
And finally pushing it into the view,
if let finalVC = createCreateFinalVC() {
yourNavController?.pushViewController(finalVC, animated: true)
}
Solution
I began a process of elimination and started to comment out all of the code in my FinalVC class. I learned that this line of code var launcher = LauncherViewController() was triggering the crash.
Given my limited beginner knowledge I don't know why this would cause a crash; I can only assume that Xcode was trying to initialize two LauncherViewControllers with identical identifier numbers or something along those lines.

Trying To Create a Slidebar Menu in IOS

I want to create a slidebar menu in my app (As shown in the image below)
When I click that hamburger icon, it should show a menu as shown below.
I am currently using the SWRevealController, a lib written in Objective C. I created a bridging header and imported the class. This is my current Set up
My initial view which branches to a Menu Controller or the UIViewTable is a SWRevealController, and the segues are subclasses of SWRevealViewControllerSegueSetController. In my Food Item View Controller (the controller where the hamburger navigation exist), I added the following code to activate the slidebar action.
override func viewDidLoad() {
super.viewDidLoad()
//Creating the slidebar Navigation using SWRevealViewController
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
}
However, when I click the button, it is still not responding. When I did this with my other application, it worked fine. I am not sure why it is not working here
This is the source I used as reference: http://www.appcoda.com/sidebar-menu-swift/
View Controller Full Code
#IBOutlet weak var thumbnail_image: UIImageView!
//#IBOutlet weak var food_detail: UITextView!
#IBOutlet weak var testing: UILabel!
#IBOutlet weak var menuButton: UIBarButtonItem!
var jsonResponseFood: NSArray = NSArray() //API for types of food available
var jsonResponseRecipe: NSArray = NSArray() // API for recipes in food
var selectedFood: foodItem?
var postStr: String?
//Initializing API
let FullRecipeAPIModel = fullRecipeAPIModel()
override func viewDidLoad() {
super.viewDidLoad()
//Creating the slidebar Navigation using SWRevealViewController
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
print(selectedFood?.name as String!)
//testing.text = self.selectedFood?.name
let APIModel = apiModel()
APIModel.delegate = self
FullRecipeAPIModel.delegate = self
APIModel.downloadItems(postString: postStr!)
// Do any additional setup after loading the view.
}
Thank you StackOverflow.
Problem in your code is you are not setting SWRevealController as root view.No Storyboard option available by code wise we have to do configuration once again. This library was designed like that. so if you change code as below it will work like a charm.
if(stat == "login"){
if(responseString == "invalid"){
self.isValid = false;
print(self.isValid)
}
DispatchQueue.main.async(execute: {
if self.checkLogin(data: responseString!) == true {
let storyboard = UIStoryboard(name: "food", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "foodItemViewController") as! foodItemViewController
let navController = UINavigationController(rootViewController: controller) // Creating a navigation controller with VC1 at the root of the navigation stack.
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let menuView :MenuController = storyboard.instantiateViewController(withIdentifier: "menuBar") as! MenuController
let revealController = SWRevealViewController()
revealController.frontViewController = navController;
revealController.rearViewController = menuView;
appDelegate.window?.rootViewController = revealController
}
else{
//Show alert here
self.showAlert(title: "User Does Not Exist", alertTitle: "Close", message: "");
}
});
}
else{
//CODE COULD BE SIMPLIFIED
DispatchQueue.main.async(execute: {
if(responseString == "duplicate"){
//Show alert here
self.showAlert(title: "User with this email already exist", alertTitle: "Close", message: "Please register with another email address")
}
else{
//Show Food UITable
let storyboard = UIStoryboard(name: "food", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "entranceFoodController")
/*let navController = UINavigationController(rootViewController: controller) // Creating a navigation controller with VC1 at the root of the navigation stack.*/
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let menuView :MenuController = storyboard.instantiateViewController(withIdentifier: "menuBar") as! MenuController
let revealController = SWRevealViewController()
revealController.frontViewController = controller;
revealController.rearViewController = menuView;
appDelegate.window?.rootViewController = revealController }
});
}
I am also working on this today, is that the best choice available to use SWRevealController, isn't there an Apple built in way of doing this?. I am eager to see options instead of getting something form Github, unless that is my last resort.

Wrong margins when instantiate view in a callback iOS

Im having a problem with the UIView margins when Instantiating it on the callback function. When the view is instantiated like this it looks normal:
let viewController = UIStoryboard(name: "Tracking", bundle: nil).instantiateViewControllerWithIdentifier("tracking") as! CarrierTrackingVC
elDrawer.mainViewController = viewController
Normal Screen
But when I instantiate in the api request callback like this, the view looks weird
TrackingController().getTruckTrack("7RZEY3VP") { (response, errs) in
if !self.requestErrors(errs) {
let truckTrack = TruckTrack(json:response["truck_track"].description)
let viewController = UIStoryboard(name: "Tracking", bundle: nil).instantiateViewControllerWithIdentifier("tracking") as! CarrierTrackingVC
elDrawer.mainViewController = viewController
}
}
Weird margins Screen
I would like to know why that happen and any clue of how could I fix it.
Thanks.
EDIT: This is the full code:
import Foundation
import UIKit
import KYDrawerController
import PKHUD
import JLToast
class MenuVC: UITableViewController {
#IBOutlet weak var fullnameLBL: UILabel!
#IBOutlet weak var profileTypeLBL: UILabel!
#IBOutlet weak var usernameLBL: UILabel!
#IBOutlet weak var profilePicIMG: RoundedImage!
#IBOutlet weak var homeLBL: UILabel!
#IBOutlet weak var servicesLBL: UILabel!
#IBOutlet weak var signOutLBL: UILabel!
#IBOutlet weak var trackingLBL: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
initContent()
NSUserDefaults.standardUserDefaults().addObserver(self, forKeyPath: PICTURE, options: NSKeyValueObservingOptions.New, context: nil)
NSUserDefaults.standardUserDefaults().addObserver(self, forKeyPath: NAME, options: NSKeyValueObservingOptions.New, context: nil)
if let url = SessionManager.sharedInstance.picture {
profilePicIMG.imageFromUrl(url)
}
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if keyPath == PICTURE {
if let url = object as? String {
profilePicIMG.imageFromUrl(url)
}
}
if keyPath == NAME {
usernameLBL.text = object as? String
}
}
deinit {
NSUserDefaults.standardUserDefaults().removeObserver(self, forKeyPath: PICTURE)
NSUserDefaults.standardUserDefaults().removeObserver(self, forKeyPath: NAME)
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath newIndexPath: NSIndexPath) {
self.tableView.deselectRowAtIndexPath(newIndexPath, animated: true)
let elDrawer = (self.navigationController?.parentViewController as! KYDrawerController)
switch newIndexPath.row {
//Profile info
case 0:
break
//Home
case 1:
elDrawer.mainViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("MainNavigation")
//Services
case 2:
elDrawer.mainViewController = UIStoryboard(name: "Services", bundle: nil).instantiateViewControllerWithIdentifier("services")
case 3:
TrackingController().getTruckTrack("7RZEY3VP") { (response, errs) in
if !self.requestErrors(errs) {
let truckTrack = TruckTrack(json:response["truck_track"].description)
let viewController = UIStoryboard(name: "Tracking", bundle: nil).instantiateViewControllerWithIdentifier("tracking") as! CarrierTrackingVC
viewController.truckTrack = truckTrack
elDrawer.mainViewController = viewController
}
}
/*let viewController = UIStoryboard(name: "Tracking", bundle: nil).instantiateViewControllerWithIdentifier("tracking") as! CarrierTrackingVC
viewController.truckTrack = TruckTrack()
elDrawer.mainViewController = viewController*/
default:
signnOut()
}
elDrawer.setDrawerState(.Closed, animated: true)
}
func signnOut() {
HUD.show(.LabeledProgress(title: NSLocalizedString("SIGNING_OUT", comment: ""), subtitle: nil))
UserController().signOut { (response, err) in
HUD.hide()
self.changeRootViewControllerWithIdentifier("start",storyboard: "Main")
}
}
func initContent() {
fullnameLBL.text = SessionManager.sharedInstance.userFullName
usernameLBL.text = SessionManager.sharedInstance.username
profileTypeLBL.text = SessionManager.sharedInstance.profileType
}
}
EDIT: viewController is a UITabBarController, each Tab contains a Navigation Controller and it's child is a View Controller.
It looks as if the vc's view is being covered by the navigation bar, which, prior to OS 6 or 7, was the default. I can't explain why the behavior would appear in one instantiation context vs the other, but you fix by setting explicitly with:
let viewController = // yada yada
viewController.edgesForExtendedLayout = UIRectEdgeNone
EDIT if I'm right that viewController is a navigation view controller, then we need it's root to adjust the edge property...
let viewController = /*yada yada*/ as! UINavigationController
let rootVC = viewController.viewControllers[0]
rootVC.edgesForExtendedLayout = UIRectEdgeNone

Unable to retrieve view controller with NSProgressIndicator programatically

I am trying to retrieve the actual view controller and call a method to change the ProgressIndicator.
I have the following function in my AppDelegate
func applicationDidFinishLaunching(_ aNotification: Notification) {
let main = NSStoryboard(name: "Main", bundle: Bundle.main)
let vc = main.instantiateController(withIdentifier: "Installing") as! ViewController
vc.incrementBar(number: 20)
}
The incrementBar function is as follows
#IBOutlet weak var progressView: NSProgressIndicator!
public func incrementBar(number: Double){
if(self.progressView != nil){
print(number)
self.progressView.increment(by: number)
}
}
Just to be sure. I can easily call this function from viewDidLoad() or viewDidAppear() but as soon as i try to receive the actual controller it tells me that progressView is nil

How to encapsulate an UIViewController (like UIAlertController) in Swift?

I have a ViewController in my Storyboard which works like an alert (with a title, a message, and two buttons).
I would like to encapsulate it to be able to use it anywhere in my code, like this :
let alert = CustomAlertViewController(title: "Test", message: "message de test.", view: self.view, delegate: self)
self.present(alert, animated: false, completion: nil)
My problem is that the IBOutlets are not initialised...
My CustomAlertViewController :
public protocol CustomAlertProtocol {
func alertAccepted()
}
class CustomAlertViewController: UIViewController {
var delegate :CustomAlertProtocol? = nil
var parentView :UIView?
var blurScreenshot :SABlurImageView?
var alertTitle :String? = nil
var alertMessage :String? = nil
#IBOutlet weak var oAlertView: UIView!
#IBOutlet weak var oAlertTitle: UILabel!
#IBOutlet weak var oAlertMessage: UILabel!
//MARK: - Main
public convenience init(title: String?, message: String?, view: UIView, delegate: CustomAlertProtocol) {
self.init()
self.alertTitle = title
self.alertMessage = message
self.delegate = delegate
self.parentView = view
}
override func viewDidLoad() {
oAlertTitle.text = self.alertTitle
oAlertMessage.text = self.alertMessage
}
#IBAction func onAcceptButtonPressed(_ sender: AnyObject) {
delegate?.alertAccepted()
}
}
Set the Custom Class property of your View Controller to CustomAlertViewController
and Storyboard ID to whatever you want - e.g. CustomAlertViewControllerIdentifier in the Identity Inspector of the InterfaceBuilder.
And then instantiate it like following:
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
guard let vc = storyboard.instantiateViewControllerWithIdentifier("CustomAlertViewControllerIdentifier") as? CustomAlertViewController else {
return
}
edit:
You can then put that code in a class function like:
extension CustomAlertViewController {
class func instantiateFromStoryboard(title: String?, message: String?, view: UIView, delegate: CustomAlertProtocol) -> CustomAlertViewController {
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateViewControllerWithIdentifier("CustomAlertViewControllerIdentifier") as! CustomAlertViewController
vc.title = title
vc.message = message
vc.view = view
vc.delegate = delegate
return vc
}
}
and then use like:
let myCustomAlertViewController = CustomAlertViewController.instantiateFromStoryboard(title: "bla", ...)

Resources