Currently, I've been following a Coursera course called Intro to Swift Programming 5. The video I was following was about the Xcode's MVC, and I'm getting the following error, even though I did what the person on screen had done:
Thread 1: Exception: "[< UIViewController 0x7fd2b6c053d0>
setValue:forUndefinedKey:]: this class is not key value
coding-compliant for the key colorLabel."
I've tried looking it up, but I don't see where I would have referenced something and deleted it. I've also checked to see if there are any warning signs near any of my reference outlets on the Main Storyboard, but everything seems to be in order there as well.
My code is as follows:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var modelLabel: UILabel!
#IBOutlet weak var colorLabel: UILabel!
#IBOutlet weak var priceLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let appleProduct = AppleProduct(name: "iPhone X", color: "Space Gray", price: 999.99)
modelLabel.text = appleProduct.name
colorLabel.text = "in \(appleProduct.color)"
priceLabel.text = "$\(appleProduct.price)"
}
}
Has anyone else experienced this issue and can help me? I'd greatly appreciate it, and I'm happy to provide any other code that's needed if this is unclear. Thanks!
CustomPrettyView is the class of the view. But you also need to declare the class of the view controller itself; otherwise Xcode will decide that it's UIViewController.
Click on the scene and in the inspector in the "Custom Class" section it will say that the class is UIViewController and it will be faded because you haven't overridden it. Change that to be the name of your view controller, which is ViewController.
I would also recommend that you change that class name to be something more meaningful, maybe PrettyViewController or something like that.
Related
Now I'm learning swift using Xcode, but I don't know where to drag and drop and why drag and drop "label" to somewhere
should I drop no.1? or no.2? or no.3? and why I should drop there?
If you drop it to 1, Xcode automatically generate an #IBOutlet for you. If you drop it to 2 or 3, then #IBAction. There's no other reason for that except that Xcode tries to be smart and help you organize code more nicely: properties with properties in the top of the class, methods – in the methods area. And you can also move declarations to another place later: except for code style matters, it doesn't matter, where exactly within your class you put declarations.
as you are trying to take an IBOutlet for a label , its nice to keep it on top of the class (where you mention 1).
normally Xcode gives suggestion you , if you drug on top side it will be #IBOutlet
or you on bottom like 2 or 3 it will be #IBAction like you already took a button action in your code .
Your Solution On Code:
import UIKit
class CodePresentViewController: UIViewController {
#IBOutlet weak var YourLabel: UILabel! // insert #IBOutlet type property here
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func tapBackButton(_ sender: UIButton) {
//Yout Button COde
}
}
If you want to own the label in your code, and then make some configuration to the label by code, use "1". It will give you a #IBOutlet label object in your code.
If you want to set the label's action, use "2" or "3".
When dragging an outlet from storyboard to a UIViewController using Xcode split view, it generates the corresponding outlet in code :
When generating the outlet code it will always be referenced as weak var ... like so :
#IBOutlet weak var titleLabel: UILabel!
However in my project the policy is to set them private and strong like so:
#IBOutlet private var titleLabel: UILabel!
Is there a way to change the default code generation within Xcode to set your own rules when binding outlets?
I think can't change default code generation. Maybe It is hardfix by algorithm in function -[IBSwiftOutletSourceCodeConnectionContext prepareToInsertSourceCode:] in IDEInterfaceBuilderKit framework.
I'm new to Swift, so sorry if this seems like an obvious question.
I'm trying to write a game in Swift, and I have designed a label and a play button in the storyboard.
I've added references to these objects in the GameViewController.swift file as seen here:
// MARK: Objects
#IBOutlet var gameLabel: UILabel!
#IBOutlet var playButton: UIImageView!
// MARK: Actions
#IBAction func playButtonTapped(sender: UITapGestureRecognizer) {
GameScene().gameStart()
}
This belongs to the GameViewController class: class GameViewController: UIViewController.
However, the main game itself takes place in GameScene.swift. This involves me having to hide the label and image as soon as the game starts. I'm unsure how to set the properties for these objects to hide, since if I did the following in GameScene.swift:
GameViewController().playButton.hidden = true
...the game crashes with a fatal error. The error says: fatal error: unexpectedly found nil while unwrapping an Optional value.
Does anyone have a suggestion for this problem? Any help is much appreciated. Sorry if the information was difficult to understand.
Cheers.
You are creating a new instance of 'GameViewController(), but you want you want use your already existent one. If you only want to create oneGameViewController`, which is probably the case, you could use a static instance variable.
In GameViewController, put:
static var instance: GameViewController!
In it's viewDidLoad(), put:
GameViewController.instance = self
Finally, in your GameScene, switch GameViewController() with GameViewController.instance.
So I have a base class UIViewController called UITabBarTopLevelViewController:
class UITabBarTopLevelViewController: UIViewController {
#IBOutlet weak var uiNavItemTitle: UINavigationItem!
override func viewDidLoad() {
super.viewDidLoad()
uiNavItemTitle.titleView = CoreUtility.LogoForUINavBarGet()
// Do any additional setup after loading the view.
}
I then have two UIViewControllers that inherit from my base class and both look like this, except the second is called MyViewController2:
class MyViewController1: UITabBarTopLevelViewController {
//#IBOutlet weak var uiNavItemTitle: UINavigationItem!
override func viewDidLoad() {
super.viewDidLoad()
//uiNavItemTitle.titleView = CoreUtility.LogoForUINavBarGet()
}
I add a Navigation Bar object to each child UIViewController super view and then I CTRL drag and add a new outlet to each UIViewController child class:
And here is the second CTRL drag outlet:
These are different references, but I can comment out the #IBOutlet weak var uiNavItemTitle: UINavigationItem! in my child classes and reference one time only in the base class UITabBarTopLevelViewController, for both MyViewController1 and MyViewController2.
You can see, when I hover over the outlet circle, in my base class, it highlights both UINavigationItem in the Story Board:
I am surprised this works, its nice for me that it works because I only need to set the uiNavItemTitle.titleView for my logo one time for both views. This is what I want but there seems to be a bit of magic that I can reference multiple outlet references one time in my base class and there is no bugs or crashes.
I currently have no memory leaks or crashes and my app is working just fine and doing exactly as I desire.
Will there be any bugs with this?
Could someone explain how this is working?
Is the fact that this works, not surprising to experienced Swift developers?
That's how subclass exactly works.
You placed a UINavigationItem in the base class UITabBarTopLevelViewController through
uiNavItemTitle.titleView = CoreUtility.LogoForUINavBarGet()
Also, MyViewController1 and MyViewController2 inherit from the base class UITabBarTopLevelViewController. That's say these child viewControllers both have a UINavigationItem which inherit from their UITabBarTopLevelViewController.
This is not a bug, on the other hand, more like a topic about design pattern though. You could place all the base stuff into a base class, inherit from those classes and implement the specific detail within the child class.
HTH.
I accidentally misspelled one of the outlet's in my view controller and ran into a few issues. When I manually try to correct the typo I get stopped at runtime within AppDelegate I'm shown the message,
Thread 1: signal SIGABRT
which highlights the beginning of the code block:
class AppDelegate: UIResponder, UIApplicationDelegate {
...
}
I've found that to fix this issue in Objective-C you would right-click the outlet's original name and "Refactor => Rename" but unfortunately I get the message:
Xcode can only refactor C and Objective-C code
View Controller
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var billTextField: UITextField!
#IBOutlet weak var tipRateSegmentedControl: UISegmentedControl!
#IBOutlet weak var tiLabel: UILabel! // Variable name should be "tipLabel"
#IBAction func calculateTapped(sender: AnyObject) {
var userInput = billTextField.text as NSString
var totalBill: Float = userInput.floatValue
var index: Int = tipRateSegmentedControl.selectedSegmentIndex
var tipRate: Float = 0.15
if index == 0 {
tipRate == 0.15
} else if index == 1 {
tipRate = 0.20
} else {
tipRate = 0.25
}
var tip: Float = totalBill * tipRate
tipLabel.text = "$\(tip)"
}
}
EDIT: Since Xcode9, there's a refactor function; the new good method is the one in this answer
Since Xcode 6, you can look for your outlet names directly in the Find navigator (Cmd+3), it shows occurrences in your code and in your xibs and storyboards. It also works with actions.
Just search the name in the Find navigator.
You can see that the second result is a reference in a storyboard. You can replace one by one by clicking on each result and press Replace, or you can directly Replace All if you are sure you don't break anything.
Refactor > Rename...
Xcode 9 had many editor improvements including a feature that changes an outlet/action name in the code and storyboard from one place.
In the example Swift code below, right click on btnRequestCode, from the popup menu select "Refactor > Rename...", change the outlet/action name and Xcode changes it in the Storyboard also.
#IBOutlet weak var btnRequestCode: UIButton!
With swift this kind of refactor doesn't work yet. You have to change the name of the outlet, and then delete and reset the connection in the interface builder.
Updated:
Right click the IBOutlet that you want to rename, delete reference outlet, and then reassign it, but you don't have to do anything with your code.
I like to fix situations like this by just opening the Storyboard as source code and editing the XML-like tags.
Right click the .storyboard file and choose "Open As". Search for the old outlet (or action/method) name that is still set in the storyboard but which no longer matches the renamed method/outlet object in the View Controller. Edit the Xml tag in the storyboard to give it the new name of your outlet or action in the view controller.