I have a ViewController subclass which segues off into multiple different other views (using a single ViewController type). I have put identifiers on the segues in the Storyboard and I want to compare them at runtime so I can pass data to them, like so:
class MyListViewController : UITableViewController {
static let segueNameFoo : String = "segueFoo"
static let segueNameBar : String = "segueBar"
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
super.prepareForSegue( segue, sender: sender )
if segue.identifier == segueNameFoo {
let vc : MyDetailViewController = segue.destinationViewController as! MyDetailViewController
vc.someData = "foo"
} else if segue.identifier == segueNameBar {
let vc : MyDetailViewController = segue.destinationViewController as! MyDetailViewController
vc.someData = "bar"
}
}
}
Problem is, Xcode 7.3 gives me these errors:
Static member segueNameFoo cannot be used on instance of type MyListViewController
Static member segueNameBar cannot be used on instance of type MyListViewController
When I change it to just let segueNameFoo : String = "segueFoo" it builds and runs fine.
I don't understand why it's complaining - segue.identifier is an NSString* and Swift supports == comparisons between them. My use of static let is so that segueNameFoo isn't allocated for every instance of MyListViewController. What's up?
Because if you use like this it means segueNameFoo is instance member
segue.identifier == segueNameFoo
is equal to
segue.identifier == self.segueNameFoo
So you should use MyListViewController.segueNameFoo. so it will be look as class member(Similarly to static)
The problem is unrelated to String vs NSString.
You have defined type properties, these are referenced as MyListViewController.segueNameFoo etc.
in swift 2 you can use this:
let str = "string"
let nsstr:NSString = "string"
if nsstr.containsString(str){
print(true)
}else{
print(false)
}
Related
I'm trying to get some information to pass to another view controller. I did the segue and nothing is showing. I'm using an external class to organize the information. But I'm not sure why it's not working.
first view controller:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toLocationVC" {
let lVC = segue.destinationViewController as! LocationViewController
lVC.locationImage?.image = locations[locationSelection].image;
lVC.nameLabel?.text = locations[locationSelection].name;
lVC.descriptionTextView?.text = locations[locationSelection].desc;
}
second view:
var selectedLocation : Location?;
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationImage.image = selectedLocation!.image
nameLabel.text = selectedLocation!.name
descriptionTextView.text = selectedLocation!.desc
}
and this is the class Location:
class Location {
var image : UIImage
var name : String
private var description : String
var desc : String {
return description + "\n\n\nThis Description and Images Provided by http://www.travel.usnews.com"
}
init(name : String, image : UIImage, description: String) {
self.name = name;
self.image = image;
self.description = description;
}
}
I've tried changing some of the code around, but nothing seems to work.
Obviously you override the information you just set prepareForSegue() in your second view controller's viewDidLoad() method.
Just remove the following code from your viewDidLoad() and it should be working (if this is actually the correct segue and all data are set):
locationImage.image = selectedLocation!.image
nameLabel.text = selectedLocation!.name
descriptionTextView.text = selectedLocation!.desc
(And I got the feeling that the selectedLocation is nil (= not set) in the viewDidLoad().)
I would rewrite the segue as follows:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "toLocationVC" {
if let lVC = segue.destinationViewController as? LocationViewController {
lVC.selectedLocation = locations[locationSelection]
}
}
Then set a breakpoint inside the if let lVC = segue...{ block to see if it's ever executed. Step through the code and use the po {variable name here} command in the debugger to look into each variable.
You shouldn't be setting anything in the viewDidLoad() function any longer like Mischa suggested. So delete those assignments.
If this answer doesn't help, I think you'll need to update your code listings to include more information. We can't see exactly where a lot of these variables are declared, or if the second view is the correct class.
I want to do like this
passing Data from A to C
like: keying some string in A, and click Button to B, then click Button to C.
show string in C's Label
I find some passing Data like this
ex:
in aClass
let bController = segue.destinationVieController
bController.string = "xxx"
But it just A to B
What should I do to passing Data from A to C ?
Now, I use NSNotificationCetner to complete this work,but I want to learn how to use segue closure
If it's really easy, please tell me keyword
because I just search A to B...
thanks!
You are passing string from A->B using segue, so you have the string now in Controller B. Pass the same string from B-> C using segue like below
let cController = segue.destinationVieController
cController.string = string
where string is the variable in Controller B which you have assigned value while segueing from A->B
You can immediately perform the segue from b->c in prepare for segue
//VCA
override func prepareForSegue(segue : UISegue, sender: AnyObject?) {
if segue.identifier == "AtoB" {
//Cast destination VC as a your B VC
let bVC = segue.destinationViewController as! BVC
//Set b's .string property to the string property you're going to send to c
bVC.string = self.string
//perform the segue that goes from b to c
bVC.performSegueWithIdentifier("BtoC")
}
}
//VCB
override func prepareForSegue(segue : UISegue, sender: AnyObject?) {
if segue.identifier == "BtoC" {
//Cast destination VC as a your C VC
let cVC = segue.destinationViewController as! CVC
//Set c's .string property to the string property that you now go from
cVC.string = self.string
//Now you will have segue'd to C passing the string you got from a
}
}
Make sure that your segue.identifier's match what you set them in storyboard.
On my app there are several views where you input certain values (settings) and so these settings get sent back to the master view using delegates. I already had this setup with 2 other views, and just copied and pasted the required code and changed the variables, however this brought up the error; "Type 'MasterViewController' does not conform to protocol 'CropPerformanceControllerDelegate'"The Code is below:
// MasterViewController
class MasterViewController: UIViewController, SettingsControllerDelegate, RainfallDataControllerDelegate, CropPerformanceControllerDelegate {
// Other variables/functions...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "MasterToSettings" {
let vc = segue.destinationViewController as! Settings
vc.delegate = self
}
if segue.identifier == "MasterToRainfallData" {
let vc = segue.destinationViewController as! RainfallData
vc.delegate = self
}
if segue.identifier == "MasterToCropPerformance" {
let vc = segue.destinationViewController as! CropPerformance
vc.delegate = self
}
}
func cropPerformanceSettingsSaved(controller: CropPerformance, irrigationResponseFactor: Double, wdImpactFactor: Double, potentialYield: Double) {
controller.navigationController?.popViewControllerAnimated(true)
irrigationResponseFactorM = irrigationResponseFactor
wdImpactFactorM = wdImpactFactor
potentialYieldM = potentialYield
}
}
// New View
// CropPerformanceView
protocol CropPerformanceControllerDelegate {
func cropPerformanceSettingsSaved(controller: CropPerformance, irrigationResponseFactor: Double, wdImpactFactor: Double, potentialYield: Double)
}
class CropPerformance: UIViewController {
var delegate: CropPerformanceControllerDelegate? = nil
// Other functions and Variables
#IBAction func updateCropSettings(sender: AnyObject) {
// Other stuff
if (delegate != nil) {
delegate!.cropPerformanceSettingsSaved(self, irrigationResponseFactor: irrigationResponseFactor!, wdImpactFactor: wdImpactFactor!, potentialYield: potentialYield!)
}
}
}
So this exact same code is used for the settings and rainfallData views and there are no issues, however now on the master view the 'CropPerformanceControllerDelegate' does not seem to be recognised and any uses of the class "CropPerformance" cause the error; "Use of undeclared type 'CropPerformance'". I hope this is enough information, all code to do with the delegate is posted, all other unnecessary variable declarations and functions I left out.
I had looked for other answers and they all said that you need to implement all required methods if you want to conform to the protocols. What exactly does that mean? All of my functions are inside my class and the code works perfectly when I remove the parts regarding the delegate.
Thanks in advance.
I was not able to solve the problem as there was no mistake in the code, I simply started from scratch, made a new document, copy and pasted the same code, changed the name to CropPerformance2 and it worked. (It works with any other name except for CropPerformance). This is very strange and must have something to do with that the initial class "CropPerformace" that I had deleted as not completely wiped from the systems memory, at least that is my assumption. In conclusion there is no answer, I simply recreated everything and it worked.
I am new in swift I am trying to send some information on click on cell of Table view using segue,but when i try to compile i get this error..
I am using Xcode 6.1 and SDK 8.1
override func prepareForSegue(segue: UIStoryboardSegue, sender:AnyObject?) {
if segue.identifier == "update"{
let selectedItems : NSManagedObject = arr[self.tableView.indexPathForSelectedRow().row] as NSManagedObject
let IVC : ViewController = segue.destinationViewController as ViewController
IVC.itemVar = selectedItems.valueForKey("item") as String
IVC.qtyVar = selectedItems.valueForKey("qty") as String
IVC.discVar = selectedItems.valueForKey("disc") as String
IVC.selectedItem = selectedItemse
}
}
You have to unwrap the returned indexPath
self.tableView.indexPathForSelectedRow()!.row
but do this only if you are sure, returned indexPath will always have value(it wont be nil)
Othrewise make the unwrapping this way:
if let indexPath = self.tableView.indexPathForSelectedRow(){
indexPath.row
}
I am using a sample from IOS 8 App Development Essentials. I added a variable to my second controller but keep getting this error.
Second controller code:
Class SocondDetailController: UIViewController{
var mastername: String?
...
}
First controller code:
override func prepareForSegue(segue: UIStoryboardSegue,sender: AnyObject?)
{
if segue.identifier == "ShowDetails"
{
let detailViewController = segue.destinationViewController as SocondDetailController
let myIndexPath = self.tableView.indexPathForSelectedRow()
let row = myIndexPath?.row
SocondDetailController.mastername = tableData[row!]
}
}
I am new to Swift and IOS development. Just starting at age 71.
I have been using VB.Net for a long time.
Please help.
Thanks.
This row:
SocondDetailController.mastername = tableData[row!]
should be:
detailViewController.mastername = tableData[row!]
mastername is an instance property, and as such you have to access to it through an instance of SocondDetailController, and not the SocondDetailController type itself.
Also, although probably not needed due to the logic in your view controller, I'd avoid using the forced unwrapping operator !, preferring a safer optional binding:
let row = myIndexPath?.row
if let row = row {
detailViewController.mastername = tableData[row]
}
or, more concisely:
if let row = myIndexPath?.row {
detailViewController.mastername = tableData[row]
}