Cannot assign values error in swift - ios

I am fiddling around with table views and I am stuck with the error Cannot assign a value of type 'Answer' to a value of type '[Answer]'
Answer is a class with the following definition:
class Answer {
var EnglishAnswer: String = ""
var ChineseAnswer: String = ""
init(newEng: String, newChi: String){
self.EnglishAnswer = newEng
self.ChineseAnswer = newChi
}
}
And I am running into problems in the prepareforsegue method:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let indexpath: NSIndexPath = self.tableView.indexPathForSelectedRow!
var DestinationViewController = segue.destinationViewController as! AnswerTableViewController
var ArrayofArrayswithAnswerElementsTwo : Answer
var ArrayofArrayswithAnswerElements = levelsArray.map( { $0.AnswersArray })
ArrayofArrayswithAnswerElementsTwo = ArrayofArrayswithAnswerElements[indexpath.row]
DestinationViewController.ArrayofArrayswithAnswerElements = ArrayofArrayswithAnswerElementsTwo
}

Error clearly stats that you are trying to assign array of Answer objects to a variable which is declared to hold only Answer objects.
This variable is meant to hold Answer object:
var ArrayofArrayswithAnswerElementsTwo : Answer
And I suspect this line is retuning an array of Answer objects:
ArrayofArrayswithAnswerElementsTwo = ArrayofArrayswithAnswerElements[indexpath.row]
You would need to put a breakpoint, check your model, print objects and check the right assignments in your prepareForSegue function.
Solution: There could be 2 solutions to your problem:
First, define ArrayofArrayswithAnswerElementsTwo like this
var ArrayofArrayswithAnswerElementsTwo : [Answer]
Second, make ArrayofArrayswithAnswerElements[indexpath.row] to return Answer and not [Answer]
PS: Naming convention of your variables is off sync with industry practice. Variable names should start with lower case and should be kept as short as possible.

Related

Cannot assign value of type 'Int' to type 'Int?.Type' Swift 5

I am trying to pass a value from one view controller to another of type Int.
Here is how I am invoking my sugue:
if questionNumber + 1 == quizBrain.quiz.count{
self.performSegue(withIdentifier: "goToScore", sender: self)
}
My prepare function is:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToScore" {
let destinationVC = segue.destination as! ResultViewController
destinationVC.finalScore = quizBrain.getScore()
}
}
Here is my destination view class:
import UIKit
class ResultViewController: UIViewController {
var finalScore = Int?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
quizBrain.getScore() fetches a value of type Int. I am trying to pass this value and catch it in the other view in var finalScore.
The error I am getting is:
Cannot assign value of type 'Int' to type 'Int?.Type'
I am not sure what this particularly means, I am new to Swift and was unable to find something similar with a type Int?.Type. I am also running into a similar issue if I try passing a String in a different project.
Changing var finalScore = Int? to var finalScore:Int = 0 fixed it! Not sure if this is a Swift version issue, would be helpful if somebody could confirm why this worked.
An optional in Swift is a type that can hold either a value or no value. Optionals are written by appending a ? to any type:
You should define an optional integer like:
var finalScore: Int? //now the value of finalScore can be nil or any integer value etc.
While using the option values, there are couple of ways:
if finalScore != nil {
print(finalScore!)
}
or
guard let score = finalScore else {
return
}
print(score)
or
print(finalScore ?? 0)
For more info, you can refer Apple Doc: https://developer.apple.com/documentation/swift/optional
Swift basics: https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399

How to get data from list type in the transferred object? (RealmSwift)

I have a realm database model object that I transfer from one controller to another. On another controller, I need to get data from this object, which stores the object of the type List. I need it in 'cellForRowAt' method.
This is my model:
class Route: Object {
#objc dynamic var routeImage: Data?
#objc dynamic var routeName: String?
#objc dynamic var numberOfPersons = 0.0
#objc dynamic var dateOfDeparture: String?
#objc dynamic var dateOfArrival: String?
let placeToVisit = List<Place>()
let person = List<Person>()
}
class Place: Object {
#objc dynamic var placeName = ""
convenience init(placeName: String) {
self.init()
self.placeName = placeName
}
}
on second VC I created:
var currentRoute: Route?
and in viewDidLoad I set:
currentRoute = UserSelectedRoute.shared.selectedRoute!
I can get data from other properties but not from the list type. I tried to implement 'reduce' method, but it doesn't work. It returns list type too. I think I need convert list to type Results but I don't know how I can return values from current object?
cellForRowAt image
As Jay suggested to me, the following solution helped me:
cell.textLabel!.text = currentRoute?.placeToVisit[indexPath.row].placeName

Passing Int property from textfield back to controller

I am trying to pass data from textfield, back to previous controller using delegation. I am stuck when I try to assign Int value in this call.
This problem is fairly easy, however I cannot find a simple solution. I have been trying different approaches with additional properties that should hold this value, but with no succeed. What do I have to do with this budgetAmount.text to be properly converted?
protocol BudgetDelegate: class {
func enteredBudgetData(info: String, info2: Int)
}
class AddBudgetViewController: UIViewController {
var budget: Budget?
weak var delegate: BudgetDelegate? = nil
#IBOutlet weak var budgetName: UITextField!
#IBOutlet weak var budgetAmount: UITextField!
//
#IBAction func saveContent(_ sender: UIButton) {
if ((budgetName.text?.isEmpty)! && (budgetAmount.text?.isEmpty)!) {
navigationController?.pop(animated: true)
} else {
-> delegate?.enteredBudgetData(info: budgetName.text!, info2: budgetAmount.text!)
navigationController?.pop(animated: true)
}
}
}
Error Cannot convert value of type 'String' to expected argument type 'Int'
The info2 parameter of your protocol method is of type Int but you are passing budgetAmount.text! which is of course a String. You need to pass an Int.
Perhaps you need to convert the text in the textfield to an Int.
delegate?.enteredBudgetData(info: budgetName.text!, info2: Int(budgetAmount.text!) ?? 0)
BTW - you are making several terrible uses of the ! operator. You should spend time learning about optionals and how to safely work with then.
So based on your question, you just want to pass an Int data coming from a UITextField. And based on your description, you do not have any problem with delegation.
Converting a String into an Int is easy:
Example:
let num = "1"
if let intNum = Int(num) {
// There you have your Integer.
}

Cannot assign value of type while passing an object

Modal class
class Trip: NSObject {
var tripTitle: String
var tripSummary: String
static var trips = [Trip]()
init(tripTitle: String, tripSummary: String) {
self.tripTitle = tripTitle
self.tripSummary = tripSummary
}
class func addTrip(tripTitle: String, tripSummary: String){
let t = Trip(tripTitle: tripTitle, tripSummary: tripSummary)
trips.append(t)
}
}
In Controller
#IBAction func previewButtomPressed(sender: UIButton) {
let tripTitle = tripTitleTxt.text!
let tripSummary = tripSummaryTxt.text!
Trip.addTrip(tripTitle, tripSummary: tripSummary)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowTripPreviewTableViewController" {
let tripPreviewTableViewController = segue.destinationViewController as! TripPreviewTableViewController
tripPreviewTableViewController.trip = Trip //here I am getting an error
}
}
error
Cannot assign value of type 'Trip.Type' to type 'Trip'
tripPreviewTableViewController
var trip : Trip!
As others have pointed out, you can't assign a Class type to a variable which represents an instance of that class, since the Class is not an instance.
However, if your class represents a trip, why does this class:
have a static class variable to hold an array of trips?
have a class method that creates a new trip and appends it to the array of trips?
If your class is meant to represent a single trip, it should only encapsulate properties and methods that refer to an instance's trip.
It seems like you're trying to also misuse the class to serve as a "global" model which happens to hold an array of trips. If you want to keep track of a collection of trips, it would make your code easier (for you and others) to understand and maintain, if you stored that array of trips outside the Trip class.
I don't know what is the type of your tripPreviewTableViewController.trip but it makes more sense for me to do:
tripPreviewTableViewController.trip = Trip.trips
Edit
Two ways to do it:
1) You change the type of tripPreviewTableViewController.trip to [Trip]?. When you assign the value you can do tripPreviewTableViewController.trip = Trip.trips
2) You can access Trip class inside your tripPreviewTableViewController.
In your case, as trips is an static variable, you do NOT need to pass anything via segue.
Just ask for Trip.trips when you needed in your destination view (TripPreviewTableViewController)

Realm Swift EXC_BAD_ACCESS During Segue with Unpersisted Object

I've got an app that I've started adding Realm to and I think I must be doing something wrong because I keep running into EXC_BAD_ACCESS when passing unpersisted objects between view controllers.
Here's a stripped down version of my app.
class TodoTask: Object {
dynamic var name: String = ""
let steps = List<Step>()
convenience init(name: String) {
self.init()
self.name = name
}
}
class Step: Object {
dynamic var name: String = ""
convenience init(name: String) {
self.init()
self.name = name
}
}
class TodoListController: UIViewController {
let todos = List<TodoTask>()
override func viewDidLoad() {
super.viewDidLoad()
var t1 = TodoTask(name: "Todo1")
let steps = [
Step("Do this"),
Step("Do that"),
]
t1.steps.appendContentsOf(steps)
var t2 = TodoTask(name: "Todo2")
let steps = [
Step("Do these"),
Step("Do those"),
]
t2.steps.appendContentsOf(steps)
todos.appendContentsOf([t1, t2])
// Display table of todos.
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let detailsController = segue.destinationViewController as? TodoDetailViewController,
let selectedTask = getSelectedTask() {
detailsController.task = selectedTask
}
}
}
class TodoDetailViewController: UIViewController {
var task: TodoTask? // <<< EXC_BAD_ACCESS
// Display the task's steps.
}
Unfortunately, I can't figure out what triggers the EXC_BAD_ACCESS and it happens intermittently. I didn't copy a stacktrace (d'oh!) but I remember it being in the C++ destructor for some sort of Row object. This is odd to me because there doesn't seem to be a database file in my Documents folder.
I'm pretty confident this is a Realm-based error because I experienced no weird crashes until I converted my plain Swift objects to Realm objects.
My only hunch is that I might be using List wrong since the warning This method can only be called during a write transaction. is in the comments of the appendContentsOf method. However, I was under the impression that I could use Realm objects that weren't stored in a Realm just like normal Swift objects.
Am I using Realm objects wrong? Is there anything else I can look into?
I'm on Realm 0.95.2.
Thanks!
Edit:
func getSelectedTask() -> TodoTask? {
if let index = taskTableView.indexPathForSelectedRow {
return tasks[index]
}
return nil
}
The issue is that a Realm List should not be created directly. This class is only used to manage to-many relationships on Object models. Instead, you should use a standard Swift array to store the unpersisted Realm Objects.
So switch:
let todos = List<TodoTask>()
to
let todos = [TodoTask]()

Resources