I've recently taken up Swift in order to learn how to program iOS apps. I've been following Skip Wilson's tutorials and there's a moment when he connects an outlet and gets:
#IBOutlet var ticTacImg1: UIImageView = nil
instead of getting that I obtain:
#IBOutlet var ticTacImg1: UIImageView!
if I try to change it Xcode tells me it's an error. What am I doing wrong?
In early versions of Xcode 6, anything marked as #IBOutlet was turned into a weak implicitly unwrapped optional.
That is
#IBOutlet var ticTacImg1: UIImageView = nil
would be compiled as
#IBOutlet weak var ticTacImg1: UIImageView! = nil
This is no longer true. Now you must declare its optional status, but it will still be weak.
That is
#IBOutlet var ticTacImg1: UIImageView! = nil
would be compiled as
#IBOutlet weak var ticTacImg1: UIImageView! = nil
The reason why ticTacImg1 is not initialized to nil is that it doesn't matter. In Swift, implicitly unwrapped optionals which are not initialized have the value nil, so = nil is redundant.
#IBOutlet var ticTacImg1: UIImageView! is the correct code.
An #IBOutlet property needs to be optional because it initially has a nil value before the system connects the view to it. Marking it as an implicitly unwrapped optional with ! means that it will be unwrapped automatically whenever it is used.
I'm not sure which specific tutorial you're referencing, but my initial thought is that he could be using an early beta of Xcode 6 that didn't enforce this.
Related
I would like to have a user input numbers and then have a calculation as the result. I have succeeded with this but I would like the user to be able to input doubles if they want too and also have the result be a double. This is my issue. I have an input TextField box and a Label result. So two Outlets. So the code I have pasted below works but only for whole numbers (ints) Hope this makes sense. Any ideas? Keep in mind I am a newbie to Swift Programming. cheers
using Xcode:
#IBOutlet weak var userInput: NSTextField!
#IBOutlet weak var result: NSTextField!
var value = 100
#IBAction func pushButtonforResult(_ sender: Any) {
result.integerValue = value / userInput.integerValue
}
I have been following a tutorial on youtube and been coding a twitter like app in xcode and keep returning this error, the tutorial was using an earlier version of swift. How do i move past this?
class HandleViewController: UIViewController {
#IBOutlet weak var fullName: UITextField!
#IBOutlet weak var handle: UITextField!
#IBOutlet weak var startTweeting: UIBarButtonItem!
#IBOutlet weak var errorMessage: UILabel!
var user = AnyObject()
var rootRef = FIRDatabase.database().reference()
override func viewDidLoad() {
super.viewDidLoad()
self.user = FIRAuth.auth()?.currentUser
}
You're getting that error because AnyObject in Swift is a Protocol, not a class, structure, or enum. A protocol is sort of a blueprint for a class, and you create classes that conform to it, but the protocol itself can never be instantiated.
As for how to fix it: It looks like the tutorial you're following uses the same code as the tutorial here. It assigns a value to user in viewDidLoad, and treats it as an optional after that. So the initial value is just a placeholder that's never getting used.
You can change the declaration to an optional instead, giving it a type but no value:
var user: AnyObject?
AnyObject has always been a Protocol in Swift, so there could never be an instance of it. So why did it work in the previous version of Swift used in the tutorial? Well for one, it looks like there's a typo in your version. In the tutorial it looks like this:
var user = AnyObject?()
The question mark after AnyObject? makes it an Optional of type AnyObject. In Swift prior to 3.0, Optional had an init() method that would create an empty instance. So AnyObject?() was shorthand for a new Optional of type AnyObject, value set to nil. In Swift 3 the superfluous initializer was dropped, so that shorthand no longer works. But just declaring the variable as an optional has the same effect.
this is a bit odd to say but essentially here is my code below:
import UIKit
class BarcodeScanPopover: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var navbar: UINavigationItem!
#IBOutlet weak var product: UILabel!
#IBOutlet weak var productimage: UIImageView!
#IBOutlet weak var scanner: UIView!
var scan: MTBBarcodeScanner = MTBBarcodeScanner(previewView: scanner);
override func viewDidLoad() {
So the issue I'm having is I can't declare "scan" without initiating the MTBBarcodeScanner object, but at the same time, I can't initiate the MTBBarcodeScanner object without calling "scanner" which is not possible at the top of the file. Unfortunately MTBBarcodeScanner() is not a valid init and causes crashes so that is not possible either.
I need to do this because I need to access "scan" at different points in the code - not just in one code method.
Any suggestions?
If you are sure you will always have an instance of the MTBBarcodeScanner after the view loaded, declare it as MTBBarcodeScanner!: var scan: MTBBarcodeScanner!. That makes it an implicitly unwrapped optional, which is allowed to be nil unless you try to access some property/function on it.
You should therefore then make sure that you always assign something to it before ever accessing it in any other way. That can and should be done in viewDidLoad:
scan = MTBBarcodeScanner(previewView: scanner)
You can let your MTBBarCodeScanner instance be an optional, and initially set it to nil.
var scan: MTBBarcodeScanner? = nil
Thereafter call your initializer to update its value as soon as scanner instance is available to you (e.g. in viewDidLoad).
I am having an issue where my NSTextField IBOutlets are showing up as nil, even though they are connected to the storyboard. In the simplified example below, I have a button that, when pressed, should list the string value of the 3 text labels.
Here is the code for the button:
import Foundation
import Cocoa
class ViewController: NSObject{
#IBAction func pushButton(sender: AnyObject) {
let oneText = Texts()
oneText.listTextFields()
}
}
Here is the code for the NSTextField list:
import Foundation
import Cocoa
class Texts: NSObject{
#IBOutlet weak var l1: NSTextField!
#IBOutlet weak var l2: NSTextField!
#IBOutlet weak var l3: NSTextField!
var textArray = [NSTextField]()
func listTextFields (){
self.textArray = [self.l1,self.l2,self.l3]
for var i = 0; i < textArray.count; i++ {
let text = textArray[i]
print(text.stringValue)
}
}
}
I have verified that the IBOutlets are all connected, but I get a "fatal error: unexpectedly found nil while unwrapping an Optional value" message when I run the program and press the button. Looking at the debugger, it appears that the tree NSTextfields are "nil."
What am I doing wrong?
You're not loading Texts from your storyboard, so it knows nothing about your outlets. Texts() creates a new instance of the object, which you then call the method on.
You presumably have an existing Texts object somewhere in interface builder, ViewController should have an outlet to that.
XCODE: Swift
Full Error:
Could not find initializer for type TableCell that accepts an argument list of type caseImage: (UIImge, caseName: String, caseDate: String)
var patientCaseArray = [TableCell]()
func loadSampleData() {
let Photo1 = UIImage(named: "retino1")!
let case1 = TableCell(caseImage: Photo1, caseName: "John Smith", caseDate: "2015-10-18" )
//error
patientCaseArray = [case1]
}
Working on a table cell class defined elsewhere, with this set of IBOutlets:
#IBOutlet weak var caseImage: UIImageView!
#IBOutlet weak var caseName: UILabel!
#IBOutlet weak var caseDate: UILabel!
I haven't done anything to the class except add the outlets.
I'm very new to swift and I'm going through a tutorial which says this is supposed to compile fine. It isn't supposed to input to the table yet. What am I missing?
Thanks in advance.
You have a discrepancy in types:
Could not find initializer for type 'TableCell' that accepts an
argument list of type caseImage: '(UIImge, caseName: String,
caseDate: String)'
and
#IBOutlet weak var caseImage: UIImageView!
UIImageView is not the same as UIImage, you will need to decide which one you want to use.