Logical AND with Swift Optional in IF statement - ios

I have two properties. One of them is optional. these are defined below:
var advertiseCompleteBlock: (() -> ())!
var isAdvertiser: Bool = false;
Now, if I try to use this in my code like below, the compiler throws an error while building and fails with error code 254.
if (self.isAdvertiser && self.advertiseCompleteBlock) {
self.advertiseCompleteBlock();
}
But if I change it like below, it works fine:
if (self.isAdvertiser && self.advertiseCompleteBlock) {
if (self.advertiseCompleteBlock) {
self.advertiseCompleteBlock();
}
}
Can anyone explain how are these two blocks of code different and what am I doing wrong here?

If advertiseCompleteBlock is really optional it should probably be declared with a ? instead of ! which says that it will always exist.
I put your original code in a test file as a simple func and removed the references to self and it compiled fine. I don't know what the error 254 would be.
Is this code really what you want?
var advertiseCompleteBlock: (() -> ())? --> really optional
var isAdvertiser: Bool = false;
if (isAdvertiser && advertiseCompleteBlock) {
advertiseCompleteBlock!(); --> but now guaranteed
}

Your block var is optional and is not initialized. So while unwrapping it will definitely be nil which compiler does not expect. That's the reason you get the compile errors.
In the second case you are checking if the var is nil or not and then calling the block, so the compiler is happy in this case.

Related

Swift: Passing callbacks to struct instance

I would like to do something along the lines of the pseudo code below:
struct Foo {
let BarInstance = Bar(Callback: CallBarInstance)
func CallBarInstance() -> Void {
BarInstance.FunctionToCall()
}
}
struct Bar {
var Callback: () -> Void
func FunctionToCall() -> Void {
print("Hello")
}
// More code that calls Callback
}
I get the error that I can't convert (Foo)->()->Void to ()->Void. I think I understand this is because the instance of Foo is being passed in as it is a member function. I figured it could then be made a static function that calls but getting access to the member variables felt hacky - is there a good way to get the functionality I want in Swift?
You seem to be trying to do something dangerous here, and Swift is stopping you from doing it.
In this line:
let BarInstance = Bar(Callback: CallBarInstance)
You are leaking an uninitialised self to Bar. Why? Because at the point in time when Bar.init is called, Foo is not be fully initialised. Namely, what is the value of BarInstance at this point? It is undefined. Yet you are trying to pass self.CallbarInstance to Bar.init!
Imagine what could happen if this were allowed. Bar.init had called the passed in function directly, before it returns. Now we have a very weird situation: CallBarInstance actually makes use of the value of BarInstance in its implementation, but what's the value of BarInstance? Bar.init hasn't returned so it's undefined!
The error message is a bit unclear though. Swift treats CallBarInstance as a (Foo) -> () -> Void in this situation (as if you were calling it as Foo.CallBarInstance), because self is unavailable.
You can kind of fix it by initialising BarInstance with some other value first, then assigning the intended Bar instance, but I don't know whether this will produce your intended behaviour or not.
struct Foo {
var BarInstance = Bar(Callback: {})
init() {
BarInstance = Bar(Callback: CallBarInstance)
}
func CallBarInstance() -> Void {
BarInstance.FunctionToCall()
}
}

variable was written, but never read?

Im getting the following warning variable 'isTaken' was written to, but never read on the following code :
func textFieldShouldEndEditing(textField: UITextField) -> Bool {
var isTaken: Bool = false
if textField == usernameTxt { var query = PFQuery(className: "_User")
query = PFQuery(className: "_User")
query.whereKey("username", equalTo: usernameTxt.text!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) in
if error == nil {
if (objects!.count > 0){
isTaken = true
}
} else {
print("Username is available. ")
}
} else {
print("error")
}
}
}
return true
}
why am I getting the warning and how do I do away with it?
As error says variable 'isTaken' was written to, but never read means you are creating isTaken instance and assigning a value to it but it never used.
Just eliminate the statements:
var isTaken: Bool = false
isTaken = true
Since the value is never used, defining and assigning to it accomplishes nothing.
Basically it's saying that isTaken is assigned a value, but it doesn't actually do anything in your code. You are never using it or checking it's value, so it's simply an warning saying that the variable is unnecessary.
If you actually are using isTaken and the compiler doesn't realize for some reason, you could probably just add another line right after
isTaken = true;
that just says
isTaken;
Or make isTaken global if you're using somewhere else in the code.
Its a compiler warning to point out a dead code. You probably have copy pasted some code and removed some unwanted code. In doing so, usage of local variable isTaken is gone. So, its only being assigned a value and never used for materializing any benefits. You can either simply remove the code around isTaken or double check and put back the functionality around it :).
It's warning you about a var that you set a value, but don't operate over it after.
Is very important keep your code clean and safe, so the xcode just gives you a little help with it.
isTaken = true;
Thats the point you set a value to isTaken variable.
Try to review your code and think about the use of this variable.
I recommend that you do not do this, but the build setting is GCC_WARN_UNUSED_VARIABLE. You can disable it, but again, do not.
I am adding the setting name here because I was searching to find it so that I could check its value in my project, but no question or answer mentioned its name.

Could not find an overload for '=='

I have the following code:
var settingButton:UIButton
settingButton = appDelegate.myFunctionReturningButton()
if (settingButton == nil) {println("WE ARE IN BAD SHAPE!!!!")}
It partly works, but not always. To see what happens in case I do not get what I expect from myFunctionReturningButton(), I added the last line.
But here is the problem and my question:
I get this error message from the Swift compiler:
Could not find an overload for '==' that accepts the supplied arguments
Browsing the net, I kind of understand what that means, but what can I do about it?
How should I write the last line?
For precision:
I have the two following function in AppDelegate.swift and appSettingButton is declared with this line at the top of the AppDelegate class.
var appSettingButton: UIButton = UIButton.alloc()
func registerSettingButton (button:UIButton) {
appSettingButton = button
}
func myFunctionReturningButton() -> UIButton {
return appSettingButton
}
You can't compare a non-optional value to nil because it will never be nil. And you shouldn't use UIButton.alloc() to initialize a button, just use UIButton(). If your logic depends on waiting for this button to be re-defined after initialization of your app delegate subclass, you should make an optional, i.e. UIButton?. Then you can compare it to nil.

Xcode 6.0.1 Segmentation Fault 11

I cannot build my project due to an error(Segmentation Fault 11). With commenting things out, I found that the error is thrown by this line:
typealias functionType = ([Expression], [String: NSNumber], inout AnyObject) -> Expression!;
If I remove the typealias and use the raw type instead, the error gets still thrown, so the mistake is probably not the typealias, but the closure.
Edit:
If I replace the type Expression with AnyObject the error gets still thrown. But if I just declare the typealias, I can use it for a global variable but not for a member variable.
I also got this error (following an online tutorial), I removed all the code I entered before to get this error and the problem persist, it seems to me as the project was corrupted. I'm not an expert so please take this report with caution.
This is happened just after appeared an error HUD telling sourceKitService Crashed...
The probably offending code was this one:
override func viewWillAppear(animated: Bool) {
if var storedtoDoItems: AnyObject! = NSUserDefaults.standardUserDefaults().objectForKey("toDoItems") {
toDoItems = []
for var i = 0; i < storedtoDoItems.count; ++i {
toDoItems.append(storedtoDoItems[i] as NSString)
}
println(storedtoDoItems)
}
taskTable.reloadData()
}

Swift function that return two strings fail when its in loop

I Wrote a function that return two Strings, when calling the function regularly its works fine, but when I'm running the function through loop, I'm getting this error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0xbfffcba0)
override func viewDidLoad()
{
super.viewDidLoad()
test()
}
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs{
var result = f(value: 1) // Fail
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
Update:
I'm using Xcode 6 beta 2, and running Mavericks on VMware Workstation.
Also, I've just created new clean project with that code and still getting the error.
This code runs fine for me. Your EXC_BAD_ACCESS must be coming from some other part of your code. Try setting a breakpoint and stepping through the code to find the line throwing the error.
From the “The Swift Programming Language.”
“An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance.”
checkButton() is an instance method, not a closure. It works in the first case because there is an implicit self. before checkButton(). It will not work in the second case.
If you want to make checkButton a closure you could declare it like so:
let checkButton = { (#value: Int) -> (location: String, pattern: String) in
return ("abc","cba")
}
I can confirm that it doesn't work for me either. Created a iOS single-view app from template, and added above code. crash. As an experiment, I took it out of the array (just f = self.checkButton) and got the same result.
I think it's a bug in the compiler.
First according to the book, a method is actually a function which is actually a closure, albeit one with special properties and restrictions. Shouldn't self.checkButton (or implicit version) be sufficient to "give it an existing instance", making it a closure? If MattL is correct that instance methods can't be used as closures, then the compiler shouldn't allow you to assign one to anything.
Second, the crash occurs on the exit, not on the call. And if you reference self in checkButton, (e.g. println(self.title) having previously set title), it works fine. That suggests that the instance is indeed known and operating, just something wrong on the return.
Third, changing it to a class method doesn't help. Changing these lines
var a = ViewController.checkButton(value: 1)
var funcs = [ViewController.checkButton]
class func checkButton(#value: Int) -> (location: String, pattern: String)
results in the same crash. I don't see any similar prohibition on context for class methods.
Fourth, if you simply change the return type from (location: String, pattern: String) to just String and return abc, then the whole thing works fine.
Fourth, if you wrap test and checkButton in a new class testClass, and then call it as below, it works:
class testClass {
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs {
var result = f(value: 1) // Fail
println(result)
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
}
class ViewController: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
let g = testClass()
g.test()
}
}
Now change testClass to testClass: NSObject and it crashes.
So it looks like the compiler is botching up a method return when called as a closure with a tuple in a Obj-C subclass. When I put it like that, I must say that it's not terribly surprising nobody's noticed yet; you're really pushing the edge here!
More practically, in the meantime, if it's helpful, an alternative to changing your method to a closure is to keep it unchanged and just wrap it as you put it in the array:
var funcs = [{value in self.checkButton(value: value)}]
This seems to work.

Resources