Swift Optional Checking "Unexpectedly found nil" - ios

I'm not sure why Swift is complaining that list1 = list1!.next unexpectedly found nil when my if statement checks if list1 != nil. Could anyone explain why checking if list1 != nil is not enough? I've tried changing it to
if list1 {
list1 = list1!.next
}
but it suggested that I check using != nil
Here's a gist
Here's my code:
class Node {
var data: Int
var next: Node?
init (data: Int) {
self.data = data
}
}
func addReversed (var list1: Node?, var list2: Node?) -> Node {
var carry = 0
var head: Node? = nil
var prev: Node? = nil
while list1 != nil || list2 != nil {
var newNode = addNode(list1, list2, &carry)
appendNode(head, prev, newNode)
if list1 != nil {
list1 = list1!.next
}
if list2 != nil {
list2 = list2!.next
}
}
if carry > 0 {
var carryNode = Node(data: carry)
appendNode(head, prev, carryNode)
}
return head!
}

This is not what you asked, but I think it may have a lot to do with the problem. I tested your Node and your basic addReversed code and I couldn't get a crash. But at that time I didn't have any of your other global functions, so I had to just comment them out while testing. Since I didn't crash, therefore I came to believe that the problem is in one of those global functions.
Then you published your gist, with the code to those global functions, and I can see immediately that this code is deeply flawed:
func appendNode(var head: Node?, var prev: Node?, node: Node) {
if head == nil {
head = node
}
if prev == nil {
prev = node
}
else {
prev!.next = node
prev = node
}
}
You seem to think that saying e.g. prev = node will replace the node that came in as prev with the node that came in as node in some outside world. It will not. These are the names of local variables only. So none of that code has any effect at all - except for prev!.next = node, because there you are mutating an instance that exists also in the outside world (because this is a reference type, a class instance).
If you want to replace the object that came in on a parameter with another object, you need an inout parameter.
For example:
class Dog {
let name:String
init(_ s:String) {
name = s
}
}
func replaceDog(var d:Dog) {
d = Dog("Rover") // this is what you are doing
}
var d = Dog("Fido")
replaceDog(d)
d // still Fido
But:
class Dog {
let name:String
init(_ s:String) {
name = s
}
}
func replaceDog(inout d:Dog) {
d = Dog("Rover")
}
var d = Dog("Fido")
replaceDog(&d)
d // Rover
Your code is full of this same false assumption, and I think, although I have not worked out the details, that this assumption is the cause of your difficulty here. My guess is that you got this linked list implementation from some other language that has pointers, but you are not using pointers in your implementation. The way to use pointers in Swift is with inout!

Related

How to mutate structs in Swift using map?

I have the following struct defined.
struct Person {
var firstName :String
var lastName :String
var active :Bool
}
I have created a collection of Person as shown below:
var persons :[Person] = []
for var i = 1; i<=10; i++ {
var person = Person(firstName: "John \(i)", lastName: "Doe \(i)", active: true)
persons.append(person)
}
and Now I am trying to change the active property to false using the code below:
let inActionPersons = persons.map { (var p) in
p.active = false
return p
}
But I get the following error:
Cannot invoke map with an argument list of type #noescape (Person) throws
Any ideas?
SOLUTION:
Looks like Swift can't infer types sometimes which is kinda lame! Here is the solution:
let a = persons.map { (var p) -> Person in
p.active = false
return p
}
THIS DOES NOT WORK:
let a = persons.map { p in
var p1 = p
p1.active = false
return p1
}
There are exactly two cases where the Swift compiler infers the return
type of a closure automatically:
In a "single-expression closure," i.e. the closure body
consists of a single expression only (with or without explicit
closure parameters).
If the type can be inferred from the calling context.
None of this applies in
let inActionPersons = persons.map { (var p) in
p.active = false
return p
}
or
let a = persons.map { p in
var p1 = p
p1.active = false
return p1
}
and that's why
you have to specify the return type explicitly as in Kametrixom's answer.
Example of a single-expression closure:
let inActionPersons = persons.map { p in
Person(firstName: p.firstName, lastName: p.lastName, active: false)
}
and it would compile with (var p) in or (p : Person) in as well, so this has nothing to do with whether the closure arguments are given
explicitly in parentheses or not.
And here is an example where the type is inferred from the calling
context:
let a : [Person] = persons.map { p in
var p1 = p
p1.active = false
return p1
}
The result of map() must be a [Person] array, so map needs
a closure of type Person -> Person, and the compiler infers
the return type Person automatically.
For more information, see "Inferring Type From Context" and "Implicit Returns from Single-Expression Closures" in the
"Closures" chapter in the Swift book.
When using the brackets for arguments so that var works, you have to put the return type as well:
let inActionPersons = persons.map { (var p) -> Person in
p.active = false
return p
}
Swift 5
The accepted answer no longer works, as of Swift 5, anyway. Closures cannot have keyword arguments anymore which means that each element of the iteration must remain a constant. Therefore, to mutate structures using map, new elements must be initialized within each iteration:
let activePersons = persons.map { (p) -> Person in
return Person(firstName: p.firstName, lastName: p.lastName, active: true)
}

Cannot Invoke Filter With Argument List '((_) -> _)' [already implemented equatable]

I am trying to use filter on an array, but I keep getting this error. I checked the earlier answer, but I have already implemented "equatable" on my object.
Btw, what does this error mean anyway?
// trying to use filter
var distance_array = [
FilterOption(title: "0.5 miles", value:500, currentSetting: false)...]
var filtered_distance: [FilterOption]!
filtered_distance = distance_array.filter({ ($0.currentValue == true) })
// FilterOption Class
class FilterOption: NSObject, Equatable {
var title:String!
var value: AnyObject?
var currentSetting: Bool!
init(title:String, value:AnyObject?, currentSetting:Bool){
self.title = title
self.value = value
self.currentSetting = currentSetting
}
class func convertDictionaryToFilterOption(dict:Dictionary<String, String>) -> FilterOption{
return FilterOption(title:dict["name"]!, value:dict["code"]!, currentSetting: false)
}
}
func == (lhs: FilterOption, rhs: FilterOption) -> Bool {
var title = (lhs.title == rhs.title)
var setting = (lhs.currentSetting! == rhs.currentSetting!)
return title && setting
}
That compiler error is a little misleading. If you were really testing to see if one FilterOption was equal to another (a common problem that rears its head when comparing objects in filter closure), then you'd have to make it conform to Equatable. But that's not the problem here.
In this case the problem is simply that the code refers to currentValue, rather than currentSetting. If you fix that, the compiler error goes away.
By the way, you can simplify that filter statement:
let filteredDistance = distanceArray.filter { $0.currentSetting }
The currentSetting is already a Bool, so if you're testing to see if it's true, you can just return it directly. There were also some extraneous parentheses.

Find Object with Property in Array

is there a possibility to get an object from an array with an specific property? Or do i need to loop trough all objects in my array and check if an property is the specific i was looking for?
edit: Thanks for given me into the correct direction, but i have a problem to convert this.
// edit again: A ok, and if there is only one specific result? Is this also a possible method do to that?
let imageUUID = sender.imageUUID
let questionImageObjects = self.formImages[currentSelectedQuestion.qIndex] as [Images]!
// this is working
//var imageObject:Images!
/*
for (index, image) in enumerate(questionImageObjects) {
if(image.imageUUID == imageUUID) {
imageObject = image
}
}
*/
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
var imageObject = questionImageObjects.filter( { return $0.imageUUID == imageUUID } )
// this is not working - NSArray is not a subtype of Images- so what if there is only 1 possible result?
You have no way to prove at compile-time that there is only one possible result on an array. What you're actually asking for is the first matching result. The easiest (though not the fastest) is to just take the first element of the result of filter:
let imageObject = questionImageObjects.filter{ $0.imageUUID == imageUUID }.first
imageObject will now be an optional of course, since it's possible that nothing matches.
If searching the whole array is time consuming, of course you can easily create a firstMatching function that will return the (optional) first element matching the closure, but for short arrays this is fine and simple.
As charles notes, in Swift 3 this is built in:
questionImageObjects.first(where: { $0.imageUUID == imageUUID })
Edit 2016-05-05: Swift 3 will include first(where:).
In Swift 2, you can use indexOf to find the index of the first array element that matches a predicate.
let index = questionImageObjects.indexOf({$0.imageUUID == imageUUID})
This is bit faster compared to filter since it will stop after the first match. (Alternatively, you could use a lazy sequence.)
However, it's a bit annoying that you can only get the index and not the object itself. I use the following extension for convenience:
extension CollectionType {
func find(#noescape predicate: (Self.Generator.Element) throws -> Bool) rethrows -> Self.Generator.Element? {
return try indexOf(predicate).map({self[$0]})
}
}
Then the following works:
questionImageObjects.find({$0.imageUUID == imageUUID})
Yes, you can use the filter method which takes a closure where you can set your logical expression.
Example:
struct User {
var firstName: String?
var lastName: String?
}
let users = [User(firstName: "John", lastName: "Doe"), User(firstName: "Bill", lastName: "Clinton"), User(firstName: "John", lastName: "Travolta")];
let johns = users.filter( { return $0.firstName == "John" } )
Note that filter returns an array containing all items satisfying the logical expression.
More info in the Library Reference
Here is a working example in Swift 5
class Point{
var x:Int
var y:Int
init(x:Int, y:Int){
self.x = x
self.y = y
}
}
var p1 = Point(x:1, y:2)
var p2 = Point(x:2, y:3)
var p3 = Point(x:1, y:4)
var points = [p1, p2, p3]
// Find the first object with given property
// In this case, firstMatchingPoint becomes p1
let firstMatchingPoint = points.first{$0.x == 1}
// Find all objects with given property
// In this case, allMatchingPoints becomes [p1, p3]
let allMatchingPoints = points.filter{$0.x == 1}
Reference:
Trailing Closure
Here is other way to fetch particular object by using object property to search an object in array.
if arrayTicketsListing.contains({ $0.status_id == "2" }) {
let ticketStatusObj: TicketsStatusList = arrayTicketsListing[arrayTicketsListing.indexOf({ $0.status_id == "2" })!]
print(ticketStatusObj.status_name)
}
Whereas, my arrayTicketsListing is [TicketsStatusList] contains objects of TicketsStatusList class.
// TicketsStatusList class
class TicketsStatusList {
internal var status_id: String
internal var status_name: String
init(){
status_id = ""
status_name = ""
}
}

Immutable array on a var?

I am getting the error:
Immutable value of type 'Array Character>' only has mutating members of name removeAtIndex()
The array should have contents because that removeAtIndex line is in a loop who's condition is if the count > 1
func evaluatePostFix(expression:Array<Character>) -> Character
{
var stack:Array<Character> = []
var count = -1 // Start at -1 to make up for 0 indexing
if expression.count == 0 {
return "X"
}
while expression.count > 1 {
if expression.count == 1 {
let answer = expression[0]
return answer
}
var expressionTokenAsString:String = String(expression[0])
if let number = expressionTokenAsString.toInt() {
stack.append(expression[0])
expression.removeAtIndex(0)
count++
} else { // Capture token, remove lefthand and righthand, solve, push result
var token = expression(count + 1)
var rightHand = stack(count)
var leftHand = stack(count - 1)
stack.removeAtIndex(count)
stack.removeAtIndex(count - 1)
stack.append(evaluateSubExpression(leftHand, rightHand, token))
}
}
}
Anyone have any idea as to why this is? Thanks!
Because all function parameters are implicitly passed by value as "let", and hence are constant within the function, no matter what they were outside the function.
To modify the value within the function (which won't affect the value on return), you can explicitly use var:
func evaluatePostFix(var expression:Array<Character>) -> Character {
...
}

Combining queries in Realm?

I have these two objects in my model:
Message:
class Message: Object {
//Precise UNIX time the message was sent
dynamic var sentTime: NSTimeInterval = NSDate().timeIntervalSince1970
let images = List<Image>()
}
Image:
class Image: Object {
dynamic var mediaURL: String = ""
var messageContainingImage: Message {
return linkingObjects(Message.self, forProperty: "images")[0]
}
}
I want to form a query which returns messages and images, messages sorted by sentTime and images sorted by their messageContainingImage's sent time. They'd be sorted together.
The recommended code for a query is this:
let messages = Realm().objects(Message).sorted("sentTime", ascending: true)
This returns a Result<Message> object. A Result doesn't have a way to be joined to another Result. There are other issues in my way too, such as, if I could combine them, how would I then perform a sort.
Additional thoughts:
I could also add a property to Image called sentTime, then once they're combined I'd be able to call that property on both of them.
I could make them both subclass from a type which has sentTime. The problem is, doing Realm().objects(Message) would only returns things which are messages, and not subclasses of Message.
How would I be able to do this?
My end goal is to display these message and image results in a tableview, messages separately from their attached image.
I think, inheritance is not the right solution here, this introduces more drawbacks by complicating your object schema, than it's worth for your use case.
Let's go back to what you wrote is your end goal: I guess you want to display messages and images together in one table view as separated rows, where the images follow their message. Do I understand that correctly?
You don't need to sort both, sorting the messages and accessing them and their images in a suitable way will ensure that everything is sorted correctly. The main challenge is more how to enumerate / random-access this two-dimensional data structure as an one-dimensional sequence.
Depending on the amount of data, you query, you have to decide, whether you can go a simple approach by keeping them all in memory at once, or introducing a view object on top of Results, which takes care of accessing all objects in order.
The first solution could just look like this:
let messages = Realm().objects(Message).sorted("sentTime", ascending: true)
array = reduce(messages, [Object]()) { (var result, message) in
result.append(message)
result += map(message.images) { $0 }
return result
}
While the latter solution is more complex, but could look like this:
// Let you iterate a list of nodes with their related objects as:
// [a<list: [a1, a2]>, b<list: [b1, b2, b3]>]
// in pre-order like:
// [a, a1, a2, b, b1, b2, b3]
// where listAccessor returns the related objects of a node, e.g.
// listAccessor(a) = [a1, a2]
//
// Usage:
// class Message: Object {
// dynamic var sentTime = NSDate()
// let images = List<Image>()
// }
//
// class Image: Object {
// …
// }
//
// FlattenedResultsView(Realm().objects(Message).sorted("sentTime"), listAccessor: { $0.images })
//
class FlattenedResultsView<T: Object, E: Object> : CollectionType {
typealias Index = Int
typealias Element = Object
let array: Results<T>
let listAccessor: (T) -> (List<E>)
var indexTransformVectors: [(Int, Int?)]
var notificationToken: NotificationToken? = nil
init(_ array: Results<T>, listAccessor: T -> List<E>) {
self.array = array
self.listAccessor = listAccessor
self.indexTransformVectors = FlattenedResultsView.computeTransformVectors(array, listAccessor)
self.notificationToken = Realm().addNotificationBlock { note, realm in
self.recomputeTransformVectors()
}
}
func recomputeTransformVectors() {
self.indexTransformVectors = FlattenedResultsView.computeTransformVectors(array, listAccessor)
}
static func computeTransformVectors(array: Results<T>, _ listAccessor: T -> List<E>) -> [(Int, Int?)] {
let initial = (endIndex: 0, array: [(Int, Int?)]())
return reduce(array, initial) { (result, element) in
var array = result.array
let list = listAccessor(element)
let vector: (Int, Int?) = (result.endIndex, nil)
array.append(vector)
for i in 0..<list.count {
let vector = (result.endIndex, Optional(i))
array.append(vector)
}
return (endIndex: result.endIndex + 1, array: array)
}.array
}
var startIndex: Index {
return indexTransformVectors.startIndex
}
var endIndex: Index {
return indexTransformVectors.endIndex
}
var count: Int {
return indexTransformVectors.count
}
subscript (position: Index) -> Object {
let vector = indexTransformVectors[position]
switch vector {
case (let i, .None):
return array[i]
case (let i, .Some(let j)):
return listAccessor(array[i])[j]
}
}
func generate() -> GeneratorOf<Object> {
var arrayGenerator = self.array.generate()
var lastObject: T? = arrayGenerator.next()
var listGenerator: GeneratorOf<E>? = nil
return GeneratorOf<Object> {
if listGenerator != nil {
let current = listGenerator!.next()
if current != nil {
return current
} else {
// Clear the listGenerator to jump back on next() to the first branch
listGenerator = nil
}
}
if let currentObject = lastObject {
// Get the list of the currentObject and advance the lastObject already, next
// time we're here the listGenerator went out of next elements and we check
// first whether there is anything on first level and start over again.
listGenerator = self.listAccessor(currentObject).generate()
lastObject = arrayGenerator.next()
return currentObject
} else {
return nil
}
}
}
}

Resources