I am just transitioning from Objective-C to Swift and have been constantly writing the following code for optional binding,
if let tempX = X {
}
My question is I have to do it so often that I need to find a new name for constant every time. What's the way to avoid having a new name tempX for every optional X in the code? Wouldn't something like work?
if let X = X {
}
Yes, you can reuse the same identifier in such bindings. But keep in mind that the redefined, non-optionalX will only be visible inside the if scope.
But if you use a guard statement, the new X may shadow the previous variable (i.e., if previous variable was defined in another scope; otherwise will trigger a compiler error). Some would say this could hurt your code readability.
For further information, please see this related question.
The new constant is only defined within the scope of your if let, so as soon as the scope is over, your tempX is gone. That also means that you can reuse names within the if let scope.
if let X = X {
}
Related
When accessing UIapplication's main window it is returned as a UIWindow??
let view = UIApplication.sharedApplication().delegate?.window // view:UIWindow??
Why is it returning as a double optional and what does it mean and if put into a if let should I add one ! after it?
if let view = UIApplication.sharedApplication().delegate?.window!
My first though was to replace ? with a ! after delegate but that was not the solution.
#matt has the details, but there is a (somewhat horrible, somewhat awesome) workaround. (See edit below, though)
let window = app.delegate?.window??.`self`()
I will leave the understanding of this line of code as an exercise for the reader.
OK, I lie, let's break it down.
app.delegate?.window
OK, so far so good. At this point we have the UIWindow?? that is giving us a headache (and I believe is a bug in Swift disconnect between Swift and Cocoa). We want to collapse it twice. We can do that with optional chaining (?.), but that unwraps and rewraps, so we're back where we started from. You can double-optional-chain, though, with ??. which is bizarre, but works.
That's great, but ?? isn't a legal suffix operator. You have to actually chain to something. Well, we want to chain back to itself (i.e. "identity"). The NSObject protocol gives us an identity method: self.
self is a method on NSObject, but it's also a reserved word in Swift, so the syntax for it is `self`()
And so we get our madness above. Do with it as you will.
Note that since ??. works, you don't technically need this. You can just accept that view is UIWindow?? and use ??. on it like view??.frame. It's a little noisy, but probably doesn't create any real problems for the few places it should be needed.
(*) I used to think of this as a bug in Swift, but it's not fixable directly by optional chaining. The problem is that there is no optional chaining past window. So I'm not sure where the right place to fix it is. Swift could allow a postfix-? to mean "flatten" without requiring chaining, but that feels odd. I guess the right operator would be interrobang delegate?.window‽ :D I'm sure that wouldn't cause any confusion.
EDIT:
Joseph Lord pointed out the better solution (which is very similar to techniques I've been using to avoid trivial if-let, but hadn't thought of this way before):
let window = app.delegate?.window ?? nil // UIWindow?
I agree with him that this is the right answer.
It's because the window property is itself in doubt (it's optional). Thus, you need one question mark because there might or might not be a window property, and another question mark because the return value of that window property is itself an Optional. Thus we get a double-wrapped Optional (as I explain in my tutorial: scroll down to the Tip box where I talk about what happens when an optional property has an Optional value).
Thus, one way to express this would be in two stages — one to cast (and unwrap that Optional), and one to fetch the window (and unwrap that Optional):
if let del = UIApplication.sharedApplication().delegate as? AppDelegate {
if let view = del.window {
Now view is a UIWindow.
Of course, if you're sure of your ground (which you probably are), you can force the cast in the first line and the unwrapping in the second line. So, in Swift 1.2:
let del = UIApplication.sharedApplication().delegate as! AppDelegate
let view = del.window!
Oh the double optional! Sometimes you can use a double-bang (two exclamation marks) but you cannot cast that way with optional binding. So... my remix of all the other code gets you a UIWindow object called window of the non-optional kind:
guard let w = UIApplication.shared.delegate?.window, let window = w else { return }
But let's not waste time and just use
let window = UIApplication.shared.delegate!.window!!
and be done.
With advent of Swift2 for me a usual workaround in this kind of cases is
if let _window = UIApplication.sharedApplication().delegate?.window, window = _window {
// Some code... i.e.
let frame = window.frame
}
class Assembly {
func getThis(value: Int) -> () -> () {
var a = value
return {
a += 1
print(a)
}
}
}
let assembly = Assembly()
let first = assembly.getThis(value: 5)
first()
first()
let second = assembly.getThis(value: 0)
second()
second()
first()
second()
gives value of:
6
7
1
2
8
3
I understand this is expected and I just want to understand how this works. I know the basics of how stack works in assembly. I think when getThis called, a new stack frame is pushed and allocate local variable a by assigning value.
But does this stack frame get popped? It looks like it does, because it returns a value means the function has finished. But on the other hand, if the stack frame is popped, the local variable on the stack frame is gone, means the a will be deallocated, obviously this isn't the case.
So how does this whole thing work?
There is a very large "gap" between Swift code and assembly code. The transformation between these two languages is vast, so I recommend you not to think "Oh wait, that wouldn't work in assembly!" because compilers are much smarter than you might think.
What basically happens here is, the closure retuned by getThis captures the local variable a. This means that a kind of "went inside" the closure. The closure now has state. This happens whenever you use self or a local variable in a closure.
How is this achieved at a low-level of abstraction? I am not really sure about how exactly the compiler works, but this kind of capturing of variables is usually done with a state machine of some kind. Therefore, your statement about a getting deallocated when getThis returns is probably not true. a will stay in memory, because it is retained by the closure. How does it do this? I can only tell you "compiler magic".
Anyway, how else do you want first to behave? Undefined behaviour? That doesn't sound Swifty. Resetting a to 0 every time you call first? That's no different from declaring a new variable again in first, is it? At the end of the day, it just seems like this "capturing" semantics is a useful thing to have in the language, so they designed Swift like so.
I am trying to make a simple addition program, but when I put my let function in the viewDidLoad, it gives me this error:
initialization of immutable value 'doMath' was never used; consider
replacing with assignment to '_' or removing it.
Here is the code
let doMath: (Int!, Int!) -> Int =
mathFunction(text1, text2)
}
What should I do?
This is something new in swift2 that is if you are not using the particular variable then replace it with _ or use that variable, that's why it suggests you to replace your variable name with _. This is mainly designed for reducing memory and CPU usage.
It is not an error. It is a warning.
initialization of immutable value 'doMath' was never used; consider replacing with assignment to '_' or removing
What this means is that you never use doMath after declaring it. As soon as you actually use doMath in your code, the warning will go away.
Yes, as stated it is a warning letting you know that you have declared a variable that has not been used either before or after the declaration. The warning message suggests that you replace the variable (doMath) with a simple (_) as doMath is not used outside of the declaration.
Your options are to ignore the warning message, or to use it outside of the declaration.
You could also set up the function completely different if you are only looking for a simple addition function.
var firstNumber = 4
var secondNumber = 6
var doMath = (firstNumber + secondNumber)
print(doMath)
Hello everyone I am trying to figure out why the swift code below allows me to assign a new value to the wee string in my class. I thought let was immutable but it works here. Can someone please explain this. Thanks.
import Foundation
class MyClass {
let wee:String
init?(inInt:Int) {
let j:String = "what"
//j = "I shouldn't be able to do this wiht let" // error rightly so
//println(j)
self.wee = "wow"
if inInt != 2 {
return nil
}
self.wee = "hey"
self.wee = "blas" // I shouldn't be able to do this
}
}
if let myClass:MyClass = MyClass(inInt: 2) {
myClass.wee // prints blas
}
The "Modifying Constant Properties During Initialization" heading under the Initialization section of The Swift Programming Language says:
You can modify the value of a constant property at any point during
initialization, as long as it is set to a definite value by the time
initialization finishes.
Reading between the lines, and considering your example, it sounds very much like restrictions on setting the value of a constant don't apply to initialization. Further evidence supporting that idea appears earlier in the same section:
When you assign a default value to a stored property, or set its
initial value within an initializer, the value of that property is set
directly, without calling any property observers.
It's not unlikely that the constancy of a stored property is enforced by the accessors for that property. If those accessors aren't used during initialization, then it makes sense that you can modify even a constant property as many times as you like during initialization.
The fact that you can't modify j in your example after first setting it is due to the fact that j is a local constant, not a property. There probably aren't any accessors for j at all -- instead the compiler probably enforces access rules for local constants/variables.
Because you are assigning it in initialiser, at a point when object of that class is being created. I just assume, it take any last given value and then creates a constant.
If you would try the same in different function, it would not work. You would get an error.
It is not possible in swift 4.
Apple docs says:
You can assign a value to a constant property at any point during initialization, as long as it is set to a definite value by the time initialization finishes. Once a constant property is assigned a value, it can't be further modified.
If I have property like:
var animatedImagesView:JSAnimatedImagesView?
And eventually it gets initialized at the proper time, do I need to just keep using ! to unwrap it ad nauseum when I want to do something to it? For instance:
self.animatedImagesView!.reloadData()
Usually I unwrap optionals like:
if let dailySleepTime:AnyObject = uw_JSON["daily_sleep_time"] {
self.settings.dailySleepTime = dailySleepTime as String
} else {
log.warning("\n Error finding attr in \(request)\n")
}
but I can't just go around casting my properties to constants in the same way right? I'm not complaining, I'm just wondering if I'm using the exclamation point correctly.
One option is to define animatedImageView as an implicitly unwrapped optional to begin with:
var animatedImagesView: JSAnimatedImagesView!
This is common when dealing with Cocoa .nib objects in Interface Builder, because the View can't be initialized until it is unarchived from the .nib, but you know that it will always be initialized before you use it.
I hate using the ! in general, because it is a runtime error just waiting to happen, but IB objects are one of the few places where its use seems both legitimate and necessary. Otherwise, your two other options are the ones that you have already found - unwrapping it every time using if let... (which is safest, but a pain in the a**), or using the ! every time that you use it, which isn't any safer than just declaring it using ! to begin with.
If you initialize it at the correct time (for example in any of the lifecycle methods, or in the constructor for that matter) you could just use ! instead of ? for the property declaration. I myself usually only use ? for stuff which I dont necessarily know will have a value at all times during my lifecycle.
If the latter is the case for you as well, you need to continue using ? since you can't guarantee you have a value stored. And you should also use the if let myVar = myVar { .. } syntax if you do multiple calls to the variable.
Instead, declare it as follows:
var animatedImagesView:JSAnimatedImagesView!
That implicitly unwrapped optional will obviate the need to constantly "bang" dereference it, but be sure it is never nil at any time accessed.
It's a great way to specify IBOutlets you know will always be initialized from the nib or storyboard before you use them.