import SpriteKit
let NumOrientations: UInt32 = 4
enum Orientation: Int, Printable {
case Zero = 0, Ninety, OneEighty, TwoSeventy
var description: String {
switch self {
case .Zero:
return "0"
case .Ninety:
return "90"
case .OneEighty:
return "180"
case .TwoSeventy:
return "270"
}
}
static func random() -> Orientation {
return Orientation(rawValue: Int(arc4random_uniform(NumOrientations)))!
}
}
I am new to swift, but I have a lot of programming experience. However, I've never encountered anything like the variable "wrapping" when dealing with unknowns in Swift.
I have the static function random, which returns an Orientation. There is NOTHING optional about the Orientation class. However, I have to use an exclamation point on the return statement in the random function.
Why is this? Excuse my complete lack of knowledge about swift.
Well, obviously the initializer can fail. Let's assume:
Orientation(rawValue: 10)
This won't find a value in your enum, so what do you expect it to return? It will return nil. That means the return value must be an optional because nil can be returned.
This is explicitly mentioned in Swift Language Guide, Enumerations, Initializing from a Raw Value:
NOTE
The raw value initializer is a failable initializer, because not every raw value will return an enumeration member. For more information, see Failable Initializers.
However, in this case (method random) you are sure that a nil won't be returned, so the best solution is to unwrap the optional before returning it from random.
Related
I tried for a long time to turn the text into an Int but it did not work. I tried it like this:
(AnzahlString is a textfield)
var AnzahlAInt = 0
if let AnzahlAString = AnzahlString.text {
let AnzahlAInt = Int(AnzahlAString)
}
But then I always get the error:
Value of optional type 'Int?' must be unwrapped to a value of type 'Int'
Then I added a ! at the end of Int(AnzahlAString)! so I don't get a error, but now when I press on the button, the app crashes. It was predictable, but how can I change this now to an Int without the !?
At first glance, it looks like you have two things to check for:
is AnzahlString.text present, and
does it represent an Int
The first check is in fact not necessary, since .text will never return nil, even though it's marked as Optional. This means you can safely force-unwrap it.
The second check is easily done by using the ?? operator:
let AnzahlAInt = Int(AnzahlString.text!) ?? 0
PS, just as a stylistic hint: variable names in Swift ususally start with a lowercase letter, names starting with capital letters are used for types.
PPS: your code as written shadows AnzahlAInt - the value of your var is never changed.
The reason why the resulting Int is optional, is that parsing might or might not succeed. For example, if you try to parse the string "Fluffy Bunnies" into an Int, there is no reasonable Int that can be returned, therefore the result of parsing that string will be nil.
Furthermore, if you force the parser by using !, you're telling Swift that you know for sure that the string you pass will always result in a valid Int, and when it doesn't, the app crashes.
You need to handle the situation in which the parse result is nil. For example:
if let AnzahlAIntResult = Int(AnzahlAString) {
// We only get here if the parse was successful and we have an Int.
// AnzahlAIntResult is now an Int, so it can be assigned to AnzahlAInt.
AnzahlAInt = AnzahlAIntResult
}
You did a good job so far but missed out one thing.
This line tries to convert the String into an Int. However this can fail, since your String can be something like this "dfhuse".
let AnzahlAInt = Int(AnzahlAString)
This is why the result of Int(AnzahlAString) is an Optional (Int?). To use it as an real Int, you have to unwrap it.
First solution is the !, however, every time this does fail your app crashes. Not a good Idea to use so.
The best solution would be Optional Binding, as you already used to get the text of your text field.
if let AnzahlAString = AnzahlString.text {
if let safeInt = Int(AnzahlAString) {
// You can use safeInt as a real Int
} else {
print("Converting your String to an Int failed badly!")
}
}
Hope this helps you. Feel free to ask again if something is unclear.
For unwrapping you can also use guard like this
Simple and easy
guard let AnzahlAInt = Int(AnzahlString.text!) else {
return
}
print(AnzahlAInt)
I have a NSObject Subclass. Say CityWalks
class CityWalks{
var totalCount:Int?
}
How do I use this property further? Should I check the nil coalescing every time this value is accessed.
example:
let aObject =
say in one fucntion (function1()) , I need to access this value, then it would like (aObject!.totalCount ?? 0)
func function1(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
Similarly in every other function(function2()) , I will have to write the same code.
func function2(){
...Some Access code for the object....
(aObject!.totalCount ?? 0)
}
So, what could be a better approach for such field, considering this property might receive a value from server or might not.
If you have a default value for this property just assign this value as default value.
class YourClass {
var totalCount = 0
}
I'd recommend you avoid using an optional value if it's possible. Because optional values its a first place when you can get an error.
As stated in the comments and the other answer using an optional is not really optimal in your case. It seems like you might as well use a default value of 0.
However, to clarify, you have to check the value when unwrapping the optional.
Sometimes it's possible to pass an optional to UIElement etc and then you don't really need to do anything with them
There are pretty ways of checking for nil in optional values built into swift so you can build pretty neat code even though you work with optional.
Look in to guard let and if let if you want to know more about unwrapping values safely.
if let
if let totalWalks = aObject?.totalCount {
//operate on totalWalks
}
guard
guard let totalWalks = aObject?.totalCount else { return }
//operate on totalWalks
There are also cases where you will want to call a function on an optional value and in this case you can do so with ?
aObject?.doSomething()
Any return values this function might have will now be wrapped in an optional and you might have to unwrap them as well with an if let or guard
When working with optionals you should try to avoid forcing the unwrap with ! as even though you at the moment know that the value is not null that might after a change in the code not be true anymore.
It may be the basic swift quetion, But i am new to swift or iOS development. I am getting the error fatal error: unexpectedly found nil while unwrapping an Optional value
For the function bellow
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false){
// Doing something
}
else
{
return nilObj!
}
}
I just want to return the nil NSData in else condition but i am getting error. I am sure i am missing something obvious, Can anybody help.
You declared nilObj as optional and initialised it with nil. Then in your else clause you are trying to unwrap that. For fixing the issue you just need to remove that !
Change your code to:
func Call() -> NSData?
{
let nilObj: NSData? = nil
if(false)
{
// Doing something
}
else
{
return nilObj
}
}
Well, error says it all! You are trying to forceful unwrap an optional. You should use if let syntax while unwrapping an optional.
Optionals in swift can be confusing at first but it helps to keep in mind that they are just an enum like:
enum Optional<T> {
case None
case Some(T) // swift enums can have data associated to them
}
If you are sure your optional has non-nil value, that is, it is a .Some, you can access this underlying value through the exclamation mark ! operator.
In short, force-unwrapping optional! is saying "Ok, I'm sure this optional contains non-nil value. Give it to me."
This is what's called force-unwrapping. You're telling the system to access the value corresponding to .Some(T) although you're not checking whether your optional is a .Some or a .None. If you force-unwrap with ! and your optional turns out to be a .None, you will get the runtime error you got unexpectedly found nil while unwrapping an Optional value.
As a rule of thumb you should always check your optionals before unwrapping them. In few occasions you should assume an optional is non-nil and force-unwrap it. Even an IBOutlet can turn out to be nil if you try to access it in prepareForSegue for example. XCode automatically makes outlets implicitly unwrapped because for most of your view controller's lifecycle they won't be nil. But you still have to take care for yourself of these less common edge cases in which they are nil.
You can check if an optional has non-nil value the standard way with
if optional != nil {
// force-unwrapping after nil check is fine
optional!.someMethod()
} else {
// 'optional' is nil
}
A more idiomatic way to do it with swift is through optional binding.
// binds the constant 'value' to your optional if it is non-nil
if let value = optional {
value.someMethod()
} else {
// optional is nil
}
A third way to check is with guard statements. The semantics of guard statements is a bit different from the previous ones though. You can also mix guard statements and optional binding.
guard optional != nil else {
// optional is nil.
// by the end of this branch you must exit the block that
// encloses the guard statement, such as with a return or break
return
}
// if control reaches here you're guaranteed optional is non-nil
Guard statements are a neat feature in swift because you can focus on the conditions you want, as opposed to what you don't want. It also keeps the code that handles a violated requirement next to the respective requirement. Compared to doing the same thing with an if statement, guards improve readability by making your intents explicit.
To know more have a look at the basics section of the swift documentation.
This question already has answers here:
Why would I use if and let together, instead of just checking if the original variable is nil? (Swift)
(2 answers)
Closed 7 years ago.
Apple has this segment of code on one of their sample projects:
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
why is apple using this if let? Isn't more logical to simply use
if cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage!
}
???!!
If you use
let existingImage = cache.objectForKey(documentIdentifier) as? UIImage
if let existingImage = existingImage where cleanThumbnailDocumentIDs.contains(documentIdentifier) {
return existingImage
}
This will make sure that if existingImage == nil,it will not
execute return existingImage.
Besides,if let also unwrap existingImage from UIImage? to
UIImage
As Abhinav mentioned above, Apple introduced a new type called optional type with Swift.
What does optional mean?
Short and Sweet, "Optional types are types, which can contain a value of a particular data type or nil".
You can read more about optionals and their advantages here : swift-optionals-made-simple
Now whenever you want to make use of value present in an optional type, first you need to check what it contains i.e. does it contains a proper value or it contains nil. This process is called optional unwrapping.
Now there are two types of unwrapping,
Forced unwrapping : If you're sure that an optional will have an value all the time, you can then unwrap the value present in the optional type using "!" mark. This is force unwrapping.
The one more way is to use if let expression, this is safe unwrapping, here you'll check in your program that, if optional has a value you will do something with it; if it doesn't contain value you'd do something else. A simple example is this (You can test this in play ground:
func printUnwrappedOptional (opt:String?) {
if let optionalValue = opt { //here we try to assign opt value to optionalValue constant, if assignment is successful control enters if block
println(optionalValue) // This will be executed only if optionalValue had some value
}
else {
println("nil")
}}
var str1:String? = "Hello World" //Declaring an optional type of string and assigning it with a value
var str2:String? //Declaring an optional type of string and not assigning any value, it defaults to nil
printUnwrappedOptional(str1) // prints "Hello World"
printUnwrappedOptional(str2) // prints "nil"
Hope this clears your question, read through the link given above it'll be more clear to you. Hope this helps. :)
Edit: In Swift 2.0, Apple introduced "guard" statements, once you're good with optionals go through this link, guard statement in swift 2. This is another way to deal with optionals.
Using if let, makes sure that the object (existingImage) is not nil, and it unwraps it automatically, so you are sure inside the if that the condition is true, and the object is not nil, and you can use it without unwrap it !
With Swift, Apple has introduced a new concept/type - Optional Type. I think you better go through Apple Documentation.
Swift also introduces optional types, which handle the absence of a
value. Optionals say either “there is a value, and it equals x” or
“there isn’t a value at all”. Optionals are similar to using nil with
pointers in Objective-C, but they work for any type, not just classes.
Optionals are safer and more expressive than nil pointers in
Objective-C and are at the heart of many of Swift’s most powerful
features.
existingImage is an optional (as? UIImage) and therefor needs to be unwrapped before used, otherwise there would be a compiler error. What you are doing is called forced unwrapping via !. Your program will crash, if existingImage == nil and is therefor only viable, if you are absolutely sure, that existingImage can't be nil
if let and optional types is more help where is there is changes to get nil values to void crashes and unwanted code executions.
In Swift 2.0,
guard
will help us lot where our intention is clear not to execute the rest of the code if that particular condition is not satisfied
ok so I am trying to return nil if a certain type is passed into my function. In this case im passing in an instance of my class "BlogPost" and a type within this blogpost. I also have an array called "types" and I have assigned the variable Videos to the last index of that array. If this type is passed into my function I would like to return nil (so assuming im going to need an optional here for returning a possible nil) this is what I have so far :-
so all in all I need to pass in an instance of my blog post but always return nil if a certain type is passed in. Hope this makes sense
Update:
The types array is defined as follows:
let types : [String] = ["technology", "Fashion", "Animals"]
this is the array I am referring to in the function. Basically if that last entry of the array is entered into the function I need to return nil
sure this is blogpost it does actually have an empty string for type
great so im getting there what Ive done now is change the blogpost.type to choose one at random. So now if the specfic type is chosen from this array how would I do that still getting an error. This is what I have updated to
so now all I need to do is access the 2 type in that array and if I do access it return nil. Any thoughts on that? so to drag it on thanks
I don't think you can. You can create failable initialisers which does what you need but you cannot use it with normal function.
The best solution for you would be return optional Int or String and when you call the function just check the result for nil and do what you need to do, otherwise ignore it:
func randomViews(blog : BlogPost.Type) -> Int? {
case 10:
return nil
case 10, 20 :
return 0
default:
random
}
if (randomViews(parameter) == nil) {
//function returned nil
}
You have displayed error because you compare optional blog to Videos, you have to unwrap it first, for example if you are sure the blog has always have a value use:
if blog! == Videos
if not sure is safer to use:
if let blg = blog {
if blg == Videos {
}
else {
// blog has not have a value
}
You are passing blog as a BlogPost.Type parameter. That is not correct. You should have either just passed it the String parameter, or you could pass it the BlogPost itself:
func randomViews(blog: BlogPost) {
let videos = types[2]
if blog.type == videos {
// do whatever you want
}
// carry on
}
Unrelated to your question at hand, but notice that I use let instead of var when defining videos. Always use let if the value will not (and cannot) change.
Also note that I use lowercase letter v in videos, because Cocoa naming conventions dictate that variables generally start with lowercase letters, whereas types, classes, structs, and enums generally start with uppercase letters.