I'd like to build a dictionary using a functional programming style. My reduce() doesn't seem to work - I get a "fatal error: unexpectedly found nil while unwrapping an Optional value"
func loadMoveToCalendarsRules(calendarIndex: Int) -> [String]? {
// return something like ["phone call", "buzz", "ring"]
return NSUserDefaults.standardUserDefaults().objectForKey(generateMoveToCalendarsRules_NSUserDefaultsKey(calendarIndex)) as? [String]
}
// Add indeces to an array of any type
func addIndices<T>(toArray: [T]) -> [(index: Int, value: T)] {
return Array(zip(toArray.indices, toArray))
}
typealias CalendarRules = [EKCalendar : [String]]?
func buildCalendarRules(cals: [EKCalendar]) -> CalendarRules {
let sortedCals = cals.sort { $0.title.lowercaseString < $1.title.lowercaseString }
// build move to cal rules.
let indexedCalList = addIndices(sortedCals)
// go through the sorted calendars and build a dictionary that associates each calendar with a string array. (These are keywords that apply to the given calendar.)
let calendarRules = indexedCalList.reduce(nil as CalendarRules) {
accumulator, nextValue in
var retVal: [EKCalendar : [String]]? = accumulator
// if there are values found in NSUserDefaults for this calendar index then retrieve them.
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
retVal![nextValue.value] = rulesForCurrentCal // fatal error: unexpectedly found nil while unwrapping an Optional value
}
return retVal
}
print("------------ built calendar rules -------------")
print(Array(arrayLiteral: calendarRules?.keys))
print(Array(arrayLiteral: calendarRules?.values))
return calendarRules
}
Your retVal is optional, and starts as nil (the initial value you pass in), yet you are using retVal! to force-unwrap it. You could just use [:] (an empty dictionary) as the initial value, and then retVal wouldn't need to be optional at all.
You are starting with nil, and never instantiate a CalendarRules dictionary, so the attempt to performed a forced unwrapping of it with ! is going to fail. Instead, test to see if it's nil and if so, instantiate one.
Before I get to that, I'd first suggest defining calendar rules as a non-optional type. It makes things less confusing this way:
typealias CalendarRules = [EKCalendar : [String]]
Then, you could use nil-coalescing operator, ??, to instantiate the CalendarRules object when needed:
let calendarRules = indexedCalList.reduce(nil as CalendarRules?) { accumulator, nextValue in
if let rulesForCurrentCal = loadMoveToCalendarsRules(nextValue.index) {
var retVal = accumulator ?? CalendarRules()
retVal[nextValue.value] = rulesForCurrentCal
return retVal
}
return accumulator
}
It strikes me that there might be more efficient approaches, but this should address your "unexpectedly found nil" error.
Related
This question already has answers here:
What is an optional value in Swift?
(15 answers)
When two optionals are assigned to an if let statement, which one gets unwrapped? Swift language
(1 answer)
Closed 5 years ago.
I've searched in a lot of places and communities among the internet to find what the heck is happening in this programing syntax.
I'm seeking, desperately, for guidance in this code.
What is happening with the compiler in these specific declarations?
transitions[prev]?[transition]
transitions[state]?[transition] != nil
This is how the class is declared
public final class StateMachine<State: Hashable, Transition: Hashable>
This is the variables
public var state: State
private var transitions = [State:[Transition:State]]()
And these are the examples:
First situation - What is happening in the transitions[prev]?[transition]
public final func advance(transition: Transition, observe: Observer? = nil) -> State {
let prev = state
if let next = transitions[prev]?[transition], next != prev {
state = next
observe?(prev, next)
}
return state
Second situation - What is happening in the return transitions[state]?[transition] != nil
public final func canAdvance(transition: Transition) -> Bool {
return transitions[state]?[transition] != nil
}
That's all i want to understand. What is happening in these moments?
The question mark operator signifies optionality in Swift.
You can declare many things a optional, meaning they could be nil or hold a value. This includes for example variable declarations, computed properties, return values of functions and callbacks/closures. Also certain operations like casting or retrieving values from dictionaries will yield optional values.
When you want to use the value contained you have to unwrap them, cause there might not be one and the may be pointing to nil. There are many ways and forms of unwrapping and optionality chaining.
Explaing your particular examples:
In a dictionary retrieving a stored value via a key as in myDict[myKey] returns an optional value. The value for the key stored within your specific dictionary is another dictionary. By declaring transitions[state]?[transition] you say basically "if there is a dictionary found for the key state, go ahead and continue with this dictionary and get the value for the key transition for that dictionary, otherwise use nil".
This code:
return transitions[state]?[transition] != nil
is basically a shorter way of writing this:
if let stateDict = transitions[state] {
return stateDict[transition] != nil
} else {
return false
}
Your other example is about an optional closure passed into a function. You can also pass optional closures into functions and call them via closure?(). The ? signifies that if nil is passed for the closure, nothing should be done, otherwise it should be executed.
This code:
observe?(prev, next)
is basically a shorter way of writing this:
if let observeClosure = observe {
observeClosure(prev, next)
}
Some more optionality explanations:
If you work with an optional value from a declared variable you can safely unwrap it like so:
func square(myValue: Int?) → Int {
guard let myValue = myValue else {
return 0
}
return myValue * myValue
}
or
func square(myValue: Int?) → Int {
if let myValue = myValue {
return myValue * myValue
} else {
return 0
}
}
or you could define a fallback with the ?? operator
func square(myValue: Int?) → Int {
return myValue ?? 0 * myValue ?? 0
}
You could also use the ! operator to unwrap unsafely and if nil is found your app would crash. You should never do that unless you can guarantee that nil cannot be found like in:
func square(myValue: Int?) → Int {
if myValue != nil {
myValue! * mayValue! {
} else {
return 0
}
}
In brief, transitions[state]?[transition] from time to time can be nil.
So, if let next = transitions[prev]?[transition] unwraps this variable moves the algorithm inside if-parenthesis
if let next = transitions[prev]?[transition] {
// this code executes here if 'transitions[prev]?[transition]' is not nil
state = next
observe?(prev, next) // this closure possibly can be nil. if nil Swift just skips this line
}
How does one use an UnsafeMutablePointer<OpaquePointer> in Swift with some Core Foundation framework? Why have an UnsafeMutablePointer<OpaquePointer>?
Given, general: some UnsafeMutablePointer<SomeType> where typealias SomeType = OpaquePointer
Specific Example API
// SOURCE: import ApplicationServices.PrintCore
typealias PMPrinter = OpaquePointer
func PMSessionGetCurrentPrinter(_ printSession: PMPrintSession, _ currentPrinter: UnsafeMutablePointer<PMPrinter>)
func PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
Specific Example Use Case: get list of papers supported by a printer
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, ¤tPrinterOptional!)
guard let currentPrinter = currentPrinterOptional else { return }
// Get the array of pre-defined PMPapers this printer supports.
// PMPrinterGetPaperList(PMPrinter, UnsafeMutablePointer<Unmanaged<CFArray>?>)
var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() as [AnyObject]? else { return }
Observed Errors
What compiles does not run. What seems like (maybe) reasonable syntax does not compile.
The above example gets the following (expected) Runtime "fatal error: unexpectedly found nil while unwrapping an Optional value".
Some select other attempts:
// Compile Error: Address of variable 'currentPrinter' taken before is is initialized
var currentPrinter: PMPrinter
PMSessionGetCurrentPrinter(printSession, ¤tPrinter)
// Compile Error: Nil cannot initialze specified type 'PMPrinter' (aka 'OpaquePointer')
var currentPrinter: PMPrinter = nil
PMSessionGetCurrentPrinter(printSession, ¤tPrinter)
// Compile Error: Variable 'currentPrinterPtr' used before being initialized
var currentPrinterPtr: UnsafeMutablePointer<PMPrinter>
PMSessionGetCurrentPrinter(printSession, currentPrinterPtr)
// Compile OK: actually compiles
// Runtime Error: unexpectedly found nil while unwrapping an Optional value
var currentPrinterOptional: PMPrinter? = nil
PMSessionGetCurrentPrinter(printSession, ¤tPrinterOptional!)
Resources
Apple: Core Printing ⇗
Apple: Using Swift with Cocoa and Objective-C ⇗
While the docs have useful information, a workable implementation for UnsafeMutablePointer<PMPrinter> with typealias as UnsafeMutablePointer<OpaquePointer> has been elusive.
PMPrinter and PMPaper are defined in the PrintCore framework
as pointer to an "incomplete type"
typedef struct OpaquePMPrinter* PMPrinter;
typedef struct OpaquePMPaper* PMPaper;
Those are imported into Swift as OpaquePointer, and are a bit
cumbersome to use.
The second argument to PMSessionGetCurrentPrinter() is a pointer to
a non-optional PMPrinter variable, and in Swift it must be
initialized before being passed as an inout argument. One possible way
to initialize a null-pointer is to use unsafeBitCast.
The easiest way to get the PMPaper objects from the array seems to
be to use CFArrayGetValueAtIndex() instead of bridging it to a
Swift array. That returns a UnsafeRawPointer which can be converted
to an OpaquePointer.
This worked in my test:
let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())
var currentPrinter = unsafeBitCast(0, to: PMPrinter.self)
PMSessionGetCurrentPrinter(printSession, ¤tPrinter);
var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() else {
fatalError()
}
for idx in 0..<CFArrayGetCount(paperList) {
let paper = PMPaper(CFArrayGetValueAtIndex(paperList, idx))!
var width = 0.0, height = 0.0
PMPaperGetWidth(paper, &width)
PMPaperGetHeight(paper, &height)
print(width, height)
}
I have a dictionary initialized
var dictionary = [String: [Double]]()
And I want to append
dictionary["Hello"].append(0.0)
but this gives me error "nil".
I tried to solve this by
extension Dictionary {
func appendish(key: String, value: Double) {
if self[key] == nil {
this give me error "Ambiguous reference to member 'subscript'"
}
}
}
How do I solve this? Been stuck at this for hours.
Subscripting a Dictionary with a key returns an optional of type Value?. In your case, dictionary["Hello"] returns a [Double]?. This optionality models the possibility that the dictionary doesn't contain a value for the given key.
If you're only dealing with static data, it's best to just use a literal expression:
let dictionary = [
"Hello": [0.0]
]
If you're using dynamic data, then there are several ways to do what you're trying to achieve, depending on how you would like to handle the nil case:
Use optional chaining
dictionary["Hello"]?.append(0.0)
This appends to the array stored for the key "Hello", but does nothing if there's no such value for that key.
This has the downside of making bugs harder to catch, because the consequence of the silent nil case might not be observed until long after this part of the code has run.
Use force unwrapping
dictionary["Hello"]!.append(0.0)
This appends to the array stored for the key "Hello", but crashes the program if there's no such value for that key.
Unlike optional chaining, this makes it easy to catch the point of failure at runtime. Of course, it comes with the drawback of crashing your program.
Handle the nil case in your own way
if var array = dictionary["Hello"] {
dictionary["Hello"] = nil // This line is a performance optimisation that removes the need for array to be copied
array.append(0.0)
dictionary["Hello"] = array
}
else {
print("No array for the key \"Hello\"") // Handle this as you wish
}
A dictionary look up returns an Optional value because the key might not exist, in which case it returns nil.
If your intention is to append to the array if it exists or create one if there isn't one yet, then the nil coalescing operator ?? comes in handy:
var dict = [String: [Double]]()
dict["hello"] = (dict["hello"] ?? []) + [1]
print(dict) // ["hello": [1.0]]
dict["hello"] = (dict["hello"] ?? []) + [2]
print(dict) // ["hello": [1.0, 2.0]]
This method does create a new array instead of mutating the existing one.
There are a few ways you can do this. Firstly, this is incorrect code:
dictionary["Hello"].append(0.0)
There might not be an array associated with the key "Hello", in which case nil will be returned by the subscript of the dictionary. So you need to unwrap it, either forced or un-forced:
dictionary["Hello"]?.append(0.0)
// or
dictionary["Hello"]!.append(0.0)
But I think what you really want to do is
if dictionary["Hello"] != nil {
dictionary["Hello"]!.append(0.0)
} else {
dictionary["Hello"] = [0.0]
}
After a long time of fiddling around with extensions and stuff (I am not familiar with this area of swift), I finally wrote the method appendish method that you were intended to write:
extension Dictionary where Value : RangeReplaceableCollection & ExpressibleByArrayLiteral, Value.Iterator.Element == Value.Element {
mutating func appendish(key: Key, value: Value.Element) {
if self[key] != nil {
self[key]!.append(value)
} else {
self[key] = [value]
}
}
}
// test
var dict = [String: [Double]]()
dict.appendish(key: "Hello", value: 0.0)
Dears
I have this case where chatId is a property of type Int
let StringMessage = String(self.listingChat?.messages.last?.chatId)
When I debug I find that StringMessage is returning Optional(15) Which means it is unwrapped. But at the same time XCode does not allow me to put any bangs (!) to unwrap it. So I am stuck with Unwrapped Variable. I know its noob question but it I really cant get it. Your help is appreciated.
Thank you
It depends on what you want the default value to be.
Assuming you want the default value to be an empty string (""), You could create a function or a method to handle it.
func stringFromChatId(chatId: Int?) -> String {
if let chatId = chatId {
return String(chatId)
} else {
return ""
}
}
let stringMessage = stringFromChatId(self.listingChat?.messages.last?.chatId)
Or you could handle it with a closure.
let stringMessage = { $0 != nil ? String($0!) : "" }(self.listingChat?.messages.last?.chatId)
If you don't mind crashing if self.listingChat?.messages.last?.chatId is nil, then you should be able to directly unwrap it.
let StringMessage = String((self.listingChat?.messages.last?.chatId)!)
or with a closure
let stringMessage = { String($0!) }(self.listingChat?.messages.last?.chatId)
Update
Assuming chatId is an Int and not an Optional<Int> (AKA Int?) I missed the most obvious unwrap answer. Sorry, I was tired last night.
let StringMessage = String(self.listingChat!.messages.last!.chatId)
Force unwrap all the optionals along the way.
Optionals have a very nice method called map (unrelated to map for Arrays) which returns nil if the variable is nil, otherwise it calls a function on the (non-nil) value. Combined with a guard-let, you get very concise code. (I've changed the case of stringMessage because variables should begin with a lower-case letter.)
guard let stringMessage = self.listingChat?.messages.last?.chatId.map { String($0) } else {
// Do failure
}
// Success. stringMessage is of type String, not String?
I think:
let StringMessage = String(self.listingChat?.messages.last?.chatId)!
I have a variable
var a: [AnyObject? -> Void]
and I am adding data in to it by append method. Now I want to check if the variable is nil or not. I tried using [] but not working and also tried "", this also not working, can anyone tell what is the meaning of this variable and how to check if it is nil.
As far as I understand, var a is an Array of functions that take an optional Object of any type, and return void. So these functions's parameter IS optional, but the Array itself isn't : it cannot be nil, or it would be declared [AnyObject? -> Void]? , no?
EDIT : if, nevertheless, you declared this a as an optional (but WHY would you do that ?) - adding a ? - you check an optional existence with if let :
if let b = a {
// a not nil, do some stuff
} else {
// a is null
}
If you just want to check if the array is empty, use isEmpty method from Swift Array
Update: Xcode 7.3 Swift 2.2
If you want to check if a variable is nil you should use if let to unwrap if for you. There is no need to create a second var.
let str = "123"
var a = Int(str)
if let a = a {
print(a)
}
Or
if let a = Int(str) {
print(a)
}
In Swift, nil is not a pointer—it is the absence of a value of a certain type. Optionals of any type can be set to nil, not just object types.
So, You can check it with below code:
let possibleNumber = "123"
let convertedNumber = possibleNumber.toInt()
if convertedNumber != nil {
println("convertedNumber contains some integer value.")
}
// prints "convertedNumber contains some integer value."
Please refer this about nil for more information.
In Swift 3.0
if let imageURL = dictObj["list_image"] as? String {
print(imageURL)
}
You can use if let. if let is a special structure in Swift that allows you to check if an Optional holds a value, and in case it does – do something with the unwrapped value.
var a:Int=0
if let b=a{
println(a)
} else {
println("Value - nil")
}
But for Strings you can also use .isEmpty() If you have initialized it to "".
var str:String=""
if !str.isEmpty(){
println(str)
}
For me none of the above solutions worked when I was using an AVFoundation object.
I would get Type 'AVCaptureDeviceInput does not conform to protocol 'BooleanType' when I tried if (audioDeviceInput) and I would get Binary operator '!=' cannot be applied to operands of type 'AVCaptureDeviceInput' and 'nil'.
Solution in my situation
if (audioDeviceInput.isEqual(nil))
nil is a pointer like any other and can be referenced as such, which is why this works.