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.
Related
Consider these lines:
I create a NSButton based class with this:
typealias onClickHandler = (NSTextfieldSuper)->Void
var onClick: onClickHandler?
When the user clicks on an instance of that button, I do this:
if (self.onClick != nil) {
onClick?(self)
}
I use that button later, from another class, with this:
let button = SuperButton()
button.onClick = { (textField: NSTextfieldSuper)->Void in
}
I am not sure if this is the correct syntax. I would like to process the button sent from the first closure on the parent class, where the button is created.
This was the only form I was able to type this without Xcode complaining. If this is correct, what is the purpose of this ->Void there? What could this possibly returning?
I just want to process that button sent.
By the way, as a bonus, I have to initialize several buttons with this, all running the same function. It would be nice to do something like
func doSomething () {
}
and then
let button = SuperButton()
button.onClick = doSomething
any ideas?
This was the only form I was able to type this without Xcode complaining. If this is correct, what is the purpose of this ->Void there? What could this possibly returning?
It is the same as in your typealias, in Swift a function type has the form:
(parameter definitions) -> return type
and functions which return nothing have a return type of Void (similar to C). The full form off a closure expression is:
{ (parameter definitions) ->return typeinbody}
Without any inference this expression provides the full type of the closure, and the -> Void Return type in your example specifies that your closure returns nothing. In your assignment this full type will be checked at compile time to conform to the type of onClick.
Now Swift will infer lots of stuff and there are various shorthands available for closure expressions, you will find that Swift accepts:
button.onClick = { textField in }
as well here with both the argument and return types of the closure being inferred.
By the way, as a bonus, [...] any ideas?
Just make the types match:
func doSomething(textField : NSTextfieldSuper) { }
button.onClick = doSomething
Unlike in (Objective-)C functions and closures (blocks in C) are interchangeable (as they are in plenty of other languages, C is the oddfellow here)
HTH
I am currently trying to get an if statement working only when the user presses on the UIButton which will then run the self.eslTopics.isHidden = false in order to show my UIPickerView. What is the correct syntax of writing the if statement? I currently have a button called "showwheel" which is meant to change the pickerview UI from hidden = true to false.
if showWheel{
self.eslTopics.isHidden = false
}
Xcode is trying to throw an error:
Optional type 'UIButton!' cannot be used as a boolean; test for '!= nil' instead, Replace 'showWheel' with '(showWheel != nil)'
which also doesn't make sense or work.
You can create a IBAction method and connect to TouchDown event of a UIButton.
#IBAction func btnShowWheelTapped(_ sender: UIButton) {
self.eslTopics.isHidden = false
}
NOTE: If you implement button's default touchup inside event then it will be called when touched is lifted from button.
For Reference...
You have to associate an IBAction with the button press and add the code in that method.
#IBAction func toggleVisibility(_ sender: UIButton) {
self.eslTopics.isHidden = false
}
if your variable showWheel is an instance variable of type UIButton! (implicitly unwrapped optional UIButton) then your code is not legal.
In C/C++/Objective-C, it's legal to say
if showWheel
And the compiler takes that to mean "if showWheel is true", and true is equivalent to !0 / !nil.
That is not legal in Swift. In Swift, you must explicitly check for nil for optionals, so your code would need to read
if showWheel != nil
Note that you should NOT put your conditional inside parentheses in Swift. Do not use if (showWheel != nil) like you would in C/C++/Objective-C/Java.
As the error mentions:
Optional type 'UIButton!' cannot be used as a boolean; test for '!=
nil' instead, Replace 'showWheel' with '(showWheel != nil)'
showWheel is type of UIButton, means that if you are typing:
if showWheel { }
it means that it is check if showWheel is nil, it is the same as:
if showWheel != nil { }
which seems to be unrelated to what are you asking for, we already assume that showWheel is not nil.
What you should do -in the IBAction of showWheel- is to call self.eslTopics.isHidden = false directly without any if statement.
If you are not familiar with adding an action to a UIButton, you could check:
How do I add a IBAction to a button programmatically in Swift 4? (programmatically).
Mahendra GP's answer (via Storyboard).
Coming from .Net, I am trying to learn Swift3/iOS and got puzzled by the following apparent inconsistent behaviour of optional protocol members. I suspect its something got to do with the juggling between objc/swift words, but what am I missing here actually?
// In playground, given below:
#objc protocol SomePtotocol {
#objc optional func someMethod()
}
class SomeDelegate: NSObject, SomePtotocol {
}
class SomeController: NSObject {
var delegate: SomePtotocol = SomeDelegate()
}
// This works and compiles without error
let controller = SomeController()
controller.delegate.someMethod?() // No error, typed as '(() -> ())?'
// But this fails to even compile ??
let delegate = SomeDelegate()
delegate.someMethod?() // Error: 'SomeDelegate' has no member 'someMethod'
I would expect either both to fail or both pass, so if someone could please enlighten me on this anomaly.
The difference between the two blocks of code is the type of the variable involved.
In the first block, delegate is explicitly typed as SomePtotocol, and this protocol defines the someMethod method, so your statement is valid.
In the second block, delegate is implicitly typed as SomeDelegate and although this class conforms to SomePtotocol, it doesn't implement the optional method someMethod, so you get an error.
If you change your second block to
let delegate: SomePtotocol = SomeDelegate()
delegate.someMethod?()
which is equivalent to the first block, then there is no error.
I am converting an iOS app from objective-c to swift. In the objective-c version of the app there was a method, AlertViewShow that gets called, and for one of its parameters nil was passed in like below.
AlertViewShow(APPNAME, INTERNET_NOT, nil);
The nil is passed in for a UIAlertViewDelegate type. Now when converting it to Swift I cannot do
AlertViewShow(APPNAME, INTERNET_NOT, nil) //error: cannot pass in nil into paramter
So, by looking at stack forums I tried this...
let alertViewNilObject: UIAlertViewDelegate? = nil
AlertViewShow(APPNAME, INTERNET_NOT, alertViewNilObject!) //compiler doesnt complain
So no errors pop up. But when I run the app it says: "fatal error: unwrapped a nil value".
How do I pass in nil into the parameter in Swift 2.0? Or is there another alternative besides passing in nil?
You need to make the argument itself take an optional value, rather than trying to force unwrap a nil optional (which will always crash).
func AlertViewShow(title:String, desc:String, delegate:AlertViewDelegate?) {
if delegate != nil {
// do some delegate-y things
}
...
}
...
AlertViewShow(title: APPNAME, desc: INTERNET_NOT, delegate: nil)
If it's an obj-c method that you're not re-writing in Swift, you'll just have to add the nullable prefix to the argument.
-(void) AlertViewShow:(NSString*)title desc:(NSString*)description delegate:(nullable UIAlertViewDelegate*)delegate;
(although it's worth noting that method names should start with a lowercase, not an uppercase)
That should then get converted to an optional argument when bridging.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
if (segue.identifier == "segueone")
{
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
if let unwrappedCellindexPath = cellIndexPath
{
var nextVC = (segue.destinationViewController as TableTwo)
nextVC.items = items[unwrappedCellindexPath.row]
}
}
}
With this piece of code, I have a few questions regarding the optionals. I recently read-through the apple developer web document as well as a few personal explanations of optionals but still have question.
Anyways,
in the line
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Is this statement only considered to be an optional because a user may not select one of the cells in my table? And with that, since I know that as long as a user wants to continue through the app, they must select a cell, I can place the exclamation point in to notify the compiler that this cell does in deed have a value(index path)?
Why does the exclamation point go after "self.tableview" and not after "sender as UITableView) in parentheses?
If my assuming is correct, I am able to use the if let syntax because I have an optional in the previous line of code?
let cellIndexPath = self.tableView!.indexPathForCell(sender as UITableViewCell)
Uses an exclamation point after tableView, because self.tableView! may not have been set (it may be nil).
It is an optional because it has the option to have a value, and it also has the option to be nil. Variables that are not optionals cannot be nil, they have to have a value.
The exclamation point goes after tableView because that is the optional which could be nil. If it went after .indexPathForCell(sender as UITableViewCell), that would imply that the value returned could be nil.
You can use the if let syntax because of this optional. This will return true if the value can be assigned to the variable. For example:
var myNilValue: String?
if(let nonNilValue = myNilValue){
//this will not be called
}
if let will return false, but:
var myNonNilValue: String? = "Hello, World!"
if(let nonNilValue = myNilValue){
//this will be called
}
Will return true.
Question marks ? are used after variable declarations to define that the variable may not have a value, and it may never have a value. They need to be unwrapped by using an exclamation point ! after the variable name. This can be used for results from a database, in case there is no result.
Exclamation points ! are used after variable declarations to define that the variable may not have a value, but it will have a value when you need to access it. They do not need to be unwrapped, but the compiler will throw an error if the variable is nil at the time of accessing it. This is typically used in #IBOutlets or #IBActions which are not defined until the program compiles
Both self.tableView and indexPathForCell() are optionals. By banging one, you only have one optional to dereference in the result. sender is also an optional and indexPathForCell() doesn't take an optional so it probably needs a bang too, but I haven't compiled it so I can't say for sure what the compiler will do.
self.tableView is reference to a property that might not have been set (e.g. is nil), so it is an optional. You can declare it for example an #IBOutlet with a ! at the end if you know it will ALWAYS be defined, such as from the Storyboard, and then you don't have to bang dereference it later.
A common thing to do is:
#IBOutlet var tableView : UITableView!
That's an implicitly unwrapped optional, and will generate an error if it's referenced when nil. But you don't need to use a ! to dereference.
Correct. The result of the line will produce an optional that you can test with if let