I am attempting to make a NSUUID with a specified value:
let uuidString = "000000-0000-0000-0000-000000000000"
let beaconUUID:NSUUID = NSUUID(UUIDString: uuidString)
The second line gives an error message:
Extra Argument 'UUIDString' in call
Looking at the documentation it seems that it should work. Any ideas?
I hace also added as String after uuidString, same issue.
The error message is misleading. init?(UUIDString string: String) is a
failable initializer" and returns an optional which has to be unwrapped. So
let beaconUUID:NSUUID = NSUUID(UUIDString: uuidString)!
or simply
let beaconUUID = NSUUID(UUIDString: uuidString)!
works. If there is any chance that the initialization fails then use optional binding:
if let beaconUUID = NSUUID(UUIDString: uuidString) {
// ...
} else {
// failed
}
For more information, see
"Failable Initializers"
in the Swift blog,
"Declarations" in "The Swift Programming Language".
NSUUID(UUIDString: uuidString)
return an optional so you have to declare your variable as optional as well.
let uuidString = "000000-0000-0000-0000-000000000000"
let beaconUUID:NSUUID? = NSUUID(UUIDString: uuidString)
Actually what is the "!" in swift? I know it is represent NOT meaning, but how come in this case it uses like this? Anyone can explain it to me, I'm new to Swift programming language.
Related
So I am teaching myself Swift and I get optionals when I am declaring them, so for example:
var thisString:String?
I would have to either force unwrap thisString, or use
if let anotherString = thisString {
or use
guard if let another string = thisString else { return }
or nil coalesce it
let anotherString = thisString ?? "Something else"
But where I am getting hung up is there are times I create something that I don't think it an optional but the compiler does.
For example, why is the URL an optional here?
let myURL = URL(string: "https://itunes.apple.com/search?term=U2")
var myRequest = URLRequest(url: myURL!)
I didn't declare it as an optional and it clearly has a value. So why does the compiler see this as an optional? If I didn't force unwrap it I would get this error:
Value of optional type 'URL?' not unwrapped; did you mean to use '!' or '?'?
Is there some standard that I am missing? I've gone over both the docs and Swift Programming Book from Big Nerd and I still don't seem to get this part.
Thanks for the assist.
But where I am getting hung up is there are times I create something that I don't think it an optional but the compiler does.
But what you think is not what matters. What matters is what the API call you are making actually returns. You find that out by reading the docs.
So why does the compiler see this as an optional
Well, let's read the docs. You are calling URL(string:). That is the same as URL's init(string:). Look at the docs:
https://developer.apple.com/documentation/foundation/url/1779737-init
The declaration is
init?(string: String)
See the question mark? That means, "This call returns an Optional." So you should expect an Optional here.
The compiler can't determine if the url that you define in the string is valid or not.
Suppose instead of:
let myURL = URL(string: "https://itunes.apple.com/search?term=U2")
You miss typed the myURL definition as:
let myURL = URL(string: "https:/itunes.apple.com/search?term=U2")
The string contains a malformed URL, so the program would crash the moment you went to define myURL.
let myURL = URL(string: "https://itunes.apple.com/search?term=U2")
Here you are creating an url from string.That string might not be a valid string.All the strings are not valid url. So you are getting an optional because if that string can be turned in to a valid url then that url will be returned else nil will be returned. See the Apple documentation here.The initializer what you are using is a failable initializer itself.
init?(string: String)
#Keshav is correct, to get a better idea, hold the option button and click on the 'string' part of the init function for the URL class. You will see in the swift reference the init declaration is init?(string: String). This means that a optional is returned. Any function can return a optional, you can have func returnMyString(_ myString: String) -> String {} or func returnMyString(_ myString: String) -> String? {}. Both of those functions are pretty much the same, except the second one returns a optional.
URL has optional initializers. For example you can have
class A {
init?() {
return nil //You will get Optional<A>.none
}
}
A() === Optional<A>.none //true
which kind of implies that initialization failed. Such initializers wrap returned object into Optional. In Swift nil == Optional<Any>.none so you can speak of them interchangeably.
For example if you will attempt to construct a URL with something that is not an actual url, it will return nil.
let notAURL = URL(string: "{") //notAURL will be nil
On a side note: I believe optional initializers are a very poor design choice since they don't communicate anything about what went wrong inside the init. If init is fallible, it should throw. I don't understand why Swift designers allow optional initializers and I see why it births a lot of confusion.
I'm trying to understand of as typecasting.
Reading Type Casting chapter on Apple Documentation, I've two syntax for downcasting (as? and as! operators) but I didn't find anything about as.
So I thought that I should never have used this kink of operator but yesterday when I was typing code with do-try-catch statement, I met this one:
catch let error as NSError {
print(error)
}
Initially, error was type conforms to the Error protocol.
Now using the as NSError casting, it has become an instance of a NSError class.
But my question is: What does as operator do?
It's not a downcasting sure.. Could it be used for "convert" object?
EDIT
I don't think it's a duplicate.
In my case, the error variable, is not a class and doesn't inherit from a super class so I have not a upcasting. It is not even a pattern matching.
I've already read both Swift Blog page and this thread on StackOverflow.
EDIT 2
From Swift Blog
Swift 1.2 separates the notions of guaranteed conversion and forced
conversion into two distinct operators. Guaranteed conversion is still
performed with the as operator, but forced conversion now uses the as!
operator. The ! is meant to indicate that the conversion may fail.
This way, you know at a glance which conversions may cause the program
to crash.
The text above doesn't work for me because if I tried to use the as! operator instead of as, compiler complain me.
EDIT 3
Even in Using Swift with Cocoa and Obj-C documentation they use the let-as? syntax for checking and casting to a protocol.
So, why in my case, I can't use it?
First of all, as suggested in the dasblinkenlight's comment, your code snippet is not using a type-casting-operator. Check the syntax of do-statement and you can find these:
catch-clause → catch patternopt where-clauseopt code-block
pattern → value-binding-pattern
value-binding-pattern → var pattern | let pattern
pattern → type-casting-pattern
type-casting-pattern → is-pattern | as-pattern
as-pattern → pattern as type
So, your EDIT 2 has no meaning, there are no syntax accepting as! in catch-clause.
But this code (using type-casting-operator) works, so I try to explain how to use as-casting.
enum MyError: Error {
case bad
//...
}
let error: Error = MyError.bad
let nsError = error as NSError
As shown in the linked article in the EI Captain v2.0's comment, as-casting is used for Guaranteed conversion. I have collected some use cases of such conversions.
Upcasting
class Animal {}
class Dog: Animal {}
let d = Dog()
d as Animal // upcast succeeds
As shown in the article, upcasting always succeeds, so you can use as.
Specifying literal type
let byte = 123 as UInt8
let ch = "a" as UnicodeScalar
In Swift, literals are typeless, so you can use as to specify the types of literals
In case Swift can infer the type of the literal, you can omit such as-casting:
let byte: UInt8 = 123
let ch: UnicodeScalar = "a"
Disambiguating overloaded methods
class MyClass {
func aMethod(_ arg: String) {
print(arg)
}
func aMethod(_ arg: Int) {
print("\"\(arg)\"")
}
}
let obj = MyClass()
let theFunc = obj.aMethod as (String)->Void
theFunc("abc") //->abc
Always-succeeds bridging
let str: String = "a String"
let nsStr = str as NSString
let intArr: [Int] = [1,2,3]
let nsArr = intArr as NSArray
The example let nsError = error as NSError is included in this category, and you need to read this article carefully, to understand why this is an always-succeeds bridging.
For your EDIT 3.
You may need to distinguish these two syntaxes:
let a: Any = 1
//Using if-let -- Optional binding, `(a as? Int)` is an expression using type-casting-operator which generates an Optional result
if let intA = (a as? Int) {
print("\(intA) is Int")
}
//Using if-case -- pattern matching, `(let intA as Int)` is a pattern using as-pattern
if case (let intA as Int) = a {
print("\(intA) is Int")
}
As already noted, catch leads a pattern, and you cannot use as? in pattern.
as
Use as for types that Apple has done some work to handle the conversion in the background. These are usually Foundation types that Apple bridged into Swift and want you to have a quick way to convert back and forth from their ObjC equivalents, for example:
String <-> NSString
URL <-> NSURL
Array <-> NSArray
Data <-> NSData
These casts always succeed and Xcode will warn you if you use as? or as!. In your specific case, Apple has done some meddling in the background to make the Error protocol and NSError to be castable to/from each other.
as!
Use as! when you know the object is castable to another type. as! will crash your app if the object is not castable (for example, when sender is actually a UITextField)
let button = sender as! UIButton // you are sure that the sender is always
// a UIButton or your app will crash
as?
Use as? when you not sure if the object is castable to the other type. In practice, this should be your preferred method and you should optional binding to check for success. as? produces nil if the object is not castable:
// Exit the function if the sender is not a UIButton
guard let sender = sender as? UIButton else {
return
}
// Only execute the block if the sender is UIButton
if let button = sender as? UIButton {
// ...
}
I am trying to load a file from my app bundle in Swift 3, and I came across a weird situation with the Swift type inferencing. If I use the following code, I get an error on the third line that says Value of optional type "String?" not unwrapped.
let url = NSURL(fileURLWithPath:Bundle.main.bundlePath)
let url2 = url.appendingPathComponent("foo.txt")
let path:String = url2?.path
To fix the error I unwrap the value on the third line by changing it to:
let path:String = url2?.path!
I now get the error Cannot force unwrap value of a non-optional type 'String'. It seems like Swift can't determine whether the path property is a String or a String?. The autocomplete feature in Xcode says it is a String, but the docs say it is a String?.
The suggested fix by Xcode for the first error was to replace url2?.path with (url2?.path)!, which finally ended up working, but I have no idea why this works and the other ways don't.
let path:String = (url2?.path)!
What is going on? Is this a type inference bug in Swift, or am I missing something super obvious
In Swift, Optional chaining like:
let path:String = url2?.path!
... is interpreted as:
let path:String = url2 != nil ? url2!.path!
: nil
As you see the type of path is non-Optional String, so the expression causes error.
(url2's type is URL?, so the type of property path is String, not String?.)
This is not a direct answer to your question, but I would re-write your code as:
let url = Bundle.main.bundleURL
let url2 = url.appendingPathComponent("foo.txt")
let path:String = url2.path
Shorter, and no worry about Optionals.
You forgot to unwrap url2
appendingPathComponent returns an optional value and you are trying to access it without unwrapping it.
So,
let url2 = url.appendingPathComponent("foo.txt")!
or
guard let url2 = url.appendingPathComponent("foo.txt") else { }
should fix it
EDIT
let path:String? = url2?.path
works also
You can also do this:
let url = Bundle.main.url(forResource: "foo", withExtension: "txt")!
let path:String = url.path
Why does this work (Example 1):
if let numString:String = Model.selectedLocation?.zip{
let callString:String = String(format:"tel:%#",numString)
//more code here
}
But not this (Example 2):
if let numString:String = String(format:"tel:%#",Model.selectedLocation?.zip){
//more code here
}
In the second example, Xcode throws an error and wants zip to be unwrapped like:
String(format:"tel:%#",(Model.selectedLocation?.zip)!)
but if I do that the app will crash when zip is nil.
QUESTION:
Is there a way to make the second example above work or is it not possible/correct?
Avoid redundant type annotations
Avoid String(format:) unless you need it. It's a method of NSString from the Foundation framework, which has several consequences:
It requires Foundation to be imported.
It implicitly bridges your String to NSString.
It won't work in Swift 3, because bridging was made explicit.
The root issue here is that String(format:) returns String? (since the format string could be invalid). You can avoid this entirely by using Swift's string interpolation:
if let numString = Model.selectedLocation?.zip {
let callString = "tel: \(numString)"
//more code here
}
...or simple concatination:
if let numString = Model.selectedLocation?.zip {
let callString = "tel: " + numString
//more code here
}
Strictly spoken Example 2 is neither optional binding nor optional chaining because String(format...) returns a non-optional String and the format parameter must be non-optional, too.
Example 1 is the correct and recommended syntax to handle the optionals.
Edit: I totally agree with Alexander's answer (except that String(format:) returns String?)
UPDATED
It is because in String(format: " ", ), the arguments must be not-nil, hence the !.
when using if-let check for optionals, statements must return optionals
// Assuming Model.selectionLocation.zip is of String type
if let numberString = Model.selectedLocation?.zip {
let formattedString = String(format:"tel:%#", numberString)
}
or use guard
guard let numberString = Model.selectedLocation?.zip else {
return
}
let numberString = String(format:"tel:%#", numberString)
I'm having a bit of a hard time wrapping my head around optionals and why they are beneficial.
First off, are these two code block essentially equivalent?
Swift:
if let unwrappedName = p.name {
var greeting = “Hello “ + unwrappedName
} else {
var greeting = “Hello stranger”
}
Objective-C:
NSString *greeting;
if (p.name) {
greeting = [NSString stringWithFormat:#"Hello %#", p.name];
} else {
greeting = #"Hello stranger"
}
Second, this is coming from the Swift iBook, I don't get any errors on these but what exactly is the difference between them??
1.
let optionalSquare: Square? = Square(sideLength: 10, name: "Optional Square")
let sideLength = optionalSquare?.numberOfSides
2.
let optionalSquare: Square! = Square(sideLength: 10, name: "Optional Square")
let sideLength = optionalSquare?.numberOfSides
3.
let optionalSquare: Square? = Square(sideLength: 10, name: "Optional Square")
let sideLength = optionalSquare!.numberOfSides
Yes, optional types are pretty similar for reference types to Objective-C references. The key difference is that non optional type can never be "nil". If the type of returned a method you are calling is Object?, you are forced to unwrap it before using it. It is clear that the response can be "empty" and the compiler will force you to handle that.
If the type is not optional then you never need to check if it is nil before using. In addition, Optional work with value types like Int. You don't need to remember if the empty value is 0 or -1 or some other magic value.
You should use optional pretty much anytime you are thinking about using a magic sentinel value that means the absence of something, ie 0, -1, nil, empty list, empty string, etc. It not hard to remember what should be checked but it is easy to forget. With optional, you do not need to "double check" its not nil, even though it "should not be nil but maybe it is". Instead, of return -1 as an index of an object that was not found return Int?. Instead of throwing an exception, when a file is not found you can pass a an optional object.
Compare with optionals:
if let mapleSyrup = shoppingList.removeAtIndex(3) {
print "Bought /(mapleSyrup)"
}
To without optionals and not perfectly clear documentation:
var mapleSyrup = shoppingList.removeAtIndex(3)
if mapleSyrup != nil && mapleSyrup.isEmpty {
print "Bought /(mapleSyrup)"
}
The second question is answered well in the swift ibook here.
let optionalSquare: Square! = Square(sideLength: 10, name: "Optional Square")
Lets you use optionalSquare as if it was a normal variable and doesn't need to be unwrapped first.
let sideLength = optionalSquare!.numberOfSides
If you know optionalSquare has a value, you can force to be unwrapped and used with !.
This article starts with some great information on the problems with nil and the benefits of optional types.