How to pass data from AKSwiftSlideMenu menu to a UIViewController in Swift? - swift

Hey guys I am using AKSwiftSlideMenu for slide menu functionality in project and I wonder if is there a way so that I can change the destination ViewController title when I segue to it from the Menu? I tried this code but is not passing the data to the destination:
func slideMenuItemSelectedAtIndex(index: Int32) {
let topViewController : UIViewController = self.navigationController!.topViewController!
print("View Controller is : \(topViewController) \n", terminator: "")
switch(index){
case 0:
print("Note\n", terminator: "")
var nextVC = AddSubcategoryVC()
nextVC.categoryName = "Note"
self.openViewControllerBasedOnIdentifier("AddSubcategoryVC")
print("On menu the cat is: \(nextVC.categoryName)")
break
default:
print("default\n", terminator: "")
}
}
On the destination viewcontroller I have this variable that is to get the data from the Menu:
var categoryName = ""
and it is returning 'nil'. I also tried doing this:
var categoryName : String!
and this:
var categoryName = String()
all returning 'nil'.

You have created new object of view controller.
Replace this code :
var nextVC = AddSubcategoryVC()
nextVC.categoryName = "Note"
self.openViewControllerBasedOnIdentifier("AddSubcategoryVC")
with
let destViewController = self.storyboard!.instantiateViewControllerWithIdentifier("AddSubcategoryVC") as! AddSubcategoryVC
destViewController.categoryName = "Note"// You have to pass your data with view controller witch will open
let topViewController : UIViewController = self.navigationController!.topViewController!
if (topViewController.restorationIdentifier! == destViewController.restorationIdentifier!){
print("Same VC")
} else {
self.navigationController!.pushViewController(destViewController, animated: true)
}

Related

Cannot assign value of type '[CollectionViewController.ViewCell]' to type '[CollectionViewController 2.ViewCell2]'

I need to pass a structure reference from one view controller to another.
Here is my code's part:
//In CollectionViewController.swift
struct ViewCell{
var lbl : String
var details: String
}
var cellDetails = [ViewCell]()
//In a action method of button tapped
let vc = CollectionViewController2.init(nibName:
"CollectionViewController2", bundle: nil)
vc.cellDetails2 = self.cellDetails
self.navigationController?.pushViewController(vc, animated: true)
//In CollectionViewController2.swift ---**
struct ViewCell2{
var lbl : String
var details: String
}
var cellDetails2 = [ViewCell2]()
code shows me error:
"Cannot assign value of type '[CollectionViewController.ViewCell]' to type '[CollectionViewController2.ViewCell2]'".
But why? How can I resolve it?

Cannot get value of switch from different VC Swift

I want to access switch value with the code below. I get nil value. From the second View controller I get settings value to display content according to the value - englishRef.
SetConViewController is my settings view controller from where I want to get my value.
let languageSettingsRef = SetConvViewController()
var englishRef = ""
// Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
if languageSettingsRef.swithEnglish.isOn{
englishRef = "yes"
}
In the View Controller below, there are switches for the settings
class SetConvViewController: UIViewController {
var conversationSettingsReference: DatabaseReference!
let userID = Auth.auth().currentUser?.uid
var engS = "engS"
var engGoster = ""
#IBOutlet weak var swithEnglish: UISwitch!
override func viewDidLoad() {
super.viewDidLoad()
if let eng2 = defaults.value(forKey: engS) {
swithEnglish.isOn = eng2 as! Bool
}
}
let defaults = UserDefaults.standard
#IBAction func switchEng(_ sender: UISwitch) {
defaults.set(sender.isOn, forKey: engS)
}
}
I get nil when I want to access value from this class.
First It's nil because you don't load the VC from storyboard or xib
Second this line
let languageSettingsRef = SetConvViewController()
is not the presented one , so use delegate or any other observing technique to get current value of the presented VC
//
class SettingsViewController: UIViewController {
var setVc:SetConvViewController?
}
when you present SettingsViewController with with segue / push , set
settInstance.setVc = self
then ask the var about the switch value
if self.setVc.swithEnglish.isOn{
englishRef = "yes"
}
Making the var as Bool is another better option

Set a UIViewController inside a switch/case statement using Swift

I am trying to load a view based on a button press. I thought I could do something like this below where I defined a generic UIViewController and then set it to a specific UIViewController inside a switch/case statement but it apparently doesn't work this way. What am I doing wrong?
#objc func menuButton(sender: UIButton) {
var view: UIViewController!
switch sender.tag {
case 0:
view = MenuViewController()
view.menuType = .Account
case 1:
view = MenuViewController()
view.menuType = .Sync
case 2:
view = AuthViewController()
view.menuType = .Auth
default: break
}
self.navigationController?.pushViewController(view, animated: true)
}
If I'm not mistaken, the compiler should give an error saying:
Value of type 'UIViewController' has no member 'menuType'
Here you have a couple of options to solve this:
Solution 1
Use casting
#objc func menuButton(sender: UIButton) {
var view: UIViewController!
switch sender.tag {
case 0:
view = MenuViewController()
(view as? MenuViewController())?.menuType = .Account
case 1:
view = MenuViewController()
(view as? MenuViewController())?.menuType = .Sync
case 2:
view = AuthViewController()
(view as? AuthViewController())?.menuType = .Auth
default: break
}
self.navigationController?.pushViewController(view, animated: true)
}
Solution 2
Create a protocol MenuProtocol
protocol MenuProtocol {
var menuType: MenuType { get set }
}
and make the MenuViewController and AuthViewController implement that protocol. Then you can do the following:
#objc func menuButton(sender: UIButton) {
var view: (UIViewController & MenuProtocol)!
switch sender.tag {
case 0:
view = MenuViewController()
view.menuType = .Account
case 1:
view = MenuViewController()
view.menuType = .Sync
case 2:
view = AuthViewController()
view.menuType = .Auth
default: break
}
self.navigationController?.pushViewController(view, animated: true)
}

Inline KVO of a Property in another view controller

I have a vc with a dynamic var "value" and i need to know when it's changed in a closure in the calling cv.
target vc:
#objc dynamic var value: String = ""
source:
if let vc: TagButtonPopupViewController = sb.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("TagPopupViewController")) as? TagButtonPopupViewController {
// configure vc
vc.value = sender.title
// observe
_ = vc.observe(\.value) { (tbvc, change) in
print("new string")
}
// present popup
presentViewController(vc, asPopoverRelativeTo: sender.bounds, of: sender, preferredEdge: NSRectEdge.maxY, behavior: NSPopover.Behavior.transient)
}
but "observe" is never called.
Any Ideas how to get notified in a closure whenever "value" has changed in Swift4?
The observer is destroyed because there is no reference
to it after the other view controller has been presented.
You have to store it
observer = vc.observe(\.value) { ... }
where observer is a property of the calling view controller.
A self-contained command-line project example: This prints "new string" as expected:
class A: NSObject {
#objc dynamic var value: String = ""
}
let a = A()
let observer = a.observe(\.value) { (_, _) in print("new string") } // (*)
a.value = "Hello world"
But nothing is printed if (*) is replaced by
_ = a.observe(\.value) { (_, _) in print("new string") }

BAD_EXC_ACCESS checking to see if data exist:SWIFT

I have a UITableViewController that I have data. If you tap on the row, you can edit the existing data, if you tap on the + in the UIBarButtonItem, you add new infomation. When my Segue passes the Core Data Object (vc.managedObjectID) my "detail" view controller checks to see if the firstName field has data or no data.
In Objective-C, I would do something like this
- (void)refreshInterface
{
CoreDataHelper *cdh = [CoreDataHelper sharedHelper];
Cues *existingCues = (Cues*)[cdh.context existingObjectWithID:_cuesNSManagedObjectID error:nil];
if (!existingCues.cuesName)
{
_cueNameTextField.text = nil;
self.cueDescriptionTextView.text = nil;
}
else
{
_cueNameTextField.text = existingCues.cuesName;
self.cueDescriptionTextView.text = existingCues.cuesDescription;
}
}
I'm having a problem checking to see if there is any data in firstName: var firstName = playerInformation.firstName causes a EXC_BAD_ACCESS only when adding a new object (meaning playerInformatin is empty), when I tap to see existing data it returns the correct data. How do I check to see if playerInfomation is empty (new record) or has data (exisiting data) in Swift?
func refreshInterface(){
if managedObjectID != nil {
var playerInformation = managedObjectContext?.existingObjectWithID(managedObjectID!, error: nil) as? PlayerInformation
var firstName = playerInformation!.firstName //EXC_BAD_ACCESS
println("firstName \(firstName)")
}
}
prepareForSegue
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "addPlayerInformationDetail" {
println("addPlayerInformationDetail")
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity
let playerInformation = NSEntityDescription.insertNewObjectForEntityForName(entity.name, inManagedObjectContext: managedObjectContext!) as PlayerInformation?
var vc = segue.destinationViewController as PlayerInformationDetailTableViewController
vc.managedObjectID = playerInformation?.objectID
} else if segue.identifier == "editPlayerInformationDetail" {
println("editPlayerInformationDetail")
var indexPath:NSIndexPath = tableView.indexPathForSelectedRow()!
var vc = segue.destinationViewController as PlayerInformationDetailTableViewController
vc.managedObjectID = self.fetchedResultsController.objectAtIndexPath(indexPath).objectID
}
You can use a conditional let like so:
if let firstName = playerInformation?.firstName {
println("firstName \(firstName)")
}
This will only unwrap the optional value if it isn't nil, avoiding the crash.
for some reason this works:
var playerInformation = managedObjectContext?.existingObjectWithID(managedObjectID!, error: nil)
var firstName: AnyObject? = playerInformation?.valueForKey("firstName")
println("firstName \(firstName)")
If I subclass the managedObjectContext as PlayerInformation, I would get EXC_BAD_ACCESS