I am trying to control drop two UILabels onto a UIViewController. I keep receiving Cannot override strong property with weak property error.
Here is a short excerpt from my code. Here is a screenshot of all the errors https://gyazo.com/bd97fa42443d12a3aa17a2de55f78b60
import UIKit
class ViewController: UIViewController {
#IBOutlet private weak var display: UILabel!
#IBOutlet private weak var description: UILabel!
private var userIsInTheMiddleOfTyping = false
#IBAction private func touchDigit(_ sender: UIButton) {
let digit = sender.currentTitle!
if (digit == "c") {
display.text = " "
} else {
print("touchDigit \(digit) digit")
if userIsInTheMiddleOfTyping {
let textCurrentlyInDisplay = display.text
if (sender.currentTitle!) == "c" {
print("it printed c")
display.text = "sam"
You need to rename your description variable since description is the name of a method inherited from NSObject (the base class of UIViewController).
You should declare your UILabels with optional type UILabel? instead UILabel!
Related
I am new both to coding and to Xcode and am working on my first iOS app - so please forgive me if the answer to my question is obvious to experienced developers.
My app works but the design looks very "old fashioned" due to the buttons I have on each View Controller. I would prefer to use a more modern navigation system using Navigation Bars with Navigation buttons at the top of each screen. However, when I use this method of navigation the global variables entered on my first View Controller cannot be accessed on my final View Controller. I have double checked my Swift code files for each View Controller which, as explained, works fine if I have UIButtons instead of the Navbar.
The only difference I can see is that the Xcode 11 Navbar system uses the "Show" (Push) method of segues between View Controllers whereas my storyboard buttons use modal presentation.
I would be grateful if someone can steer me in the right direction - thanks!
The code showing the global variables from the first view controller is:
\\
import UIKit
var name = ""
var lastname = ""
var address = ""
var city = ""
var zip = ""
var email = ""
var phone = ""
var dateofbirth = ""
class ViewController1: UIViewController {
#IBOutlet weak var outlet: UITextField!
#IBOutlet weak var outlet2: UITextField!
#IBOutlet weak var outlet6: UITextField!
#IBOutlet weak var outlet3: UITextField!
#IBOutlet weak var outlet4: UITextField!
#IBOutlet weak var outlet5: UITextField!
#IBOutlet weak var outlet8: UITextField!
#IBOutlet weak var outlet7: UITextField!
#IBAction func submit(_ sender: Any) {
// Code for First Name
if (outlet.text != "")
{
name = outlet.text!
}
// Code for Last Name
if (outlet2.text != "")
{
lastname = outlet2.text!
}
// Code for Address
if (outlet3.text != "")
{
address = outlet3.text!
}
// Code for city
if (outlet4.text != "")
{
city = outlet4.text!
}
// Code for Zip
if (outlet5.text != "")
{
zip = outlet5.text!
}
// Code for Email
if (outlet6.text != "")
{
email = outlet6.text!
}
// Code for Phone
if (outlet7.text != "")
{
phone = outlet7.text!
}
// Code for Date of Birth
if (outlet8.text != "")
{
dateofbirth = outlet8.text!
}
// Dismissal of Keyboard
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
super.touchesBegan(touches, with: event)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
\\\\
The code for the final View Controller is:
\\\\
import UIKit
class ReportViewController: UIViewController {
//Client ID Label Outlets
#IBOutlet weak var Label: UILabel!
#IBOutlet weak var Label2: UILabel!
#IBOutlet weak var Label3: UILabel!
#IBOutlet weak var Label4: UILabel!
#IBOutlet weak var Label5: UILabel!
#IBOutlet weak var Label6: UILabel!
#IBOutlet weak var Label7: UILabel!
#IBOutlet weak var Label8: UILabel!
// Return function
#IBAction func unwindToReportVC (_sender:UIStoryboardSegue){
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated:Bool){
// Client ID Labels text using declared global variables
Label.text = name
Label2.text = lastname
Label3.text = address
Label4.text = city
Label5.text = zip
Label6.text = email
Label7.text = phone
Label8.text = dateofbirth
}
}
I am having some trouble updating my secondViewController view in Xcode using Swift 5. I want my app to add two numbers together and show the result in the second ViewController. Although it works the first time, if I return to my previous view and change the numbers, the view does not update.
I tried using viewWillAppear, viewWillDisappear, amongst others, including NSNotificationCenter addObserve, but I have had no luck whatsoever.
Do you have any recommendations? Am I missing something?
Please see below for the code and a screenshot of my ViewControllers:
//
// ViewController.swift
//
import UIKit
var result = ""
var resultFinal = Float(result)
let finalResult = resultFinal!
class ViewController: UIViewController {
#IBOutlet weak var firstNumber: UITextField!
#IBOutlet weak var secondNumber: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func getResult()-> Float{
guard let fNumber = firstNumber.text else {
return 0
}
let firstFloat = Float(fNumber)
guard let sNumber = secondNumber.text else {
return 0
}
let secondFloat = Float(sNumber)
let sumNumber: Float = firstFloat! + secondFloat!
return sumNumber
}
#IBAction func submitSum(_ sender: Any) {
resultFinal = getResult()
print(resultFinal!)
}
}
//
// secondViewController.swift
//
import UIKit
class secondViewController: UIViewController {
#IBOutlet weak var test: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
self.test.text!=""
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
test.text = String(finalResult)
}
}
Screenshot:
Thanks.
Your problem is with the global variables. It seems from your code that you expect these three to reevaluate every time one of them changes:
var result = ""
var resultFinal = Float(result)
let finalResult = resultFinal!
For example, if you set resultFinal = 4, then finalResult will equal 4. However, those variables only evaluate once––the first time. You can simplify your use of these variables significantly. Replace these three with:
var result: Float?
Then, in ViewController:
class ViewController: UIViewController {
#IBOutlet weak var firstNumber: UITextField!
#IBOutlet weak var secondNumber: UITextField!
func getResult() -> Float {
guard let number1 = Float(firstNumber.text ?? "0") ?? 0
guard let number2 = Float(secondNumber.text ?? "0") ?? 0
return number1 + number2
}
#IBAction func submitSum(_ sender: Any) {
result = getResult()
}
}
Note: I simplified getResult and made it treat empty fields as 0.
In SecondViewController:
class SecondViewController: UIViewController {
#IBOutlet weak var test: UITextField!
override func viewWillAppear(_ animated: Bool) {
test.text = String(result ?? 0)
}
}
Note: self.test.text!="" doesn't really do anything, so I removed it.
How can I not repeat the array when I click on the button in swift? I'm trying to generate fruits without them repeating. Can I sort the string that way it runs through all the fruits one by one? It doesn't have to be randomized. I just want each word to show only once when I click the button and show the last array "There aren't any fruit options left"
I tried to randomize the string but that repeats the fruits. I just want it to go one by one. When I press the button on my screen the output on the image label should give me each fruit one at a time.
ie. Button pressed"
Output: "Apple"
button pressed again
Output: "Banana"
and so on until the last string shows "There aren't any fruit options left"
import UIKit
class fruitrandomViewController: UIViewController {
#IBOutlet weak var nextfruitButton: UIButton!
#IBOutlet weak var fruitbox: UILabel!
#IBAction func fruitbutton(_ sender: UIButton) {
let array = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear","T"There aren't any fruit options left",]
let randomFruitgenerator = Int(arc4random_uniform(UInt32(array.count)))
fruitbox.text = array[randomFruitgenerator]
}
}
You need to somehow keep track of the array elements that you have already used. You could do this in a couple of ways:
Keep an index property that tracks the next element of the array
Mutate the array itself as elements are consumed
Either way, you should make the array an instance property, not a local variable in the function itself.
Here is an example of the second approach (I prefer this since I think it makes the code a little simpler, as you don't need to track the next index).
class fruitrandomViewController: UIViewController {
#IBOutlet weak var nextfruitButton: UIButton!
#IBOutlet weak var fruitbox: UILabel!
var fruit = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear",].shuffled()
#IBAction func fruitbutton(_ sender: UIButton) {
if fruit.isEmpty {
fruitbox.text = "There's no more fruit left"
} else {
fruitbox.text = self.fruit[0]
self.fruit.remove(at:0)
}
}
}
For completeness, here is the first approach (with an added "previous fruit" button):
class fruitrandomViewController: UIViewController {
#IBOutlet weak var nextfruitButton: UIButton!
#IBOutlet weak var fruitbox: UILabel!
let fruit = ["Apple","Banana","Orange","Pinapple", "Plum", "Pear",].shuffled()
var nextFruit = 0
#IBAction func fruitbutton(_ sender: UIButton) {
if nextFruit < fruit.count {
fruitbox.text = self.fruit[nextFruit]
nextFruit += 1
} else {
fruitbox.text = "There's no more fruit left"
}
}
#IBAction func previousFruitButton(_ sender: UIButton) {
guard nextFruit > 0 else {
return
}
nextFruit -= 1
fruitbox.text = self.fruit[nextFruit]
}
}
If you don't want the fruit in a random order, just remove the .shuffled()
I have a problem I can't seem to solve myself, I have two view controllers, the first one contains three variables that stores integers. On my second view controller I have 3 sliders which manipulates a label under each slider with a number.
I want the numbers from these 3 sliders to replace the numbers that were set in the three variables on my first view controller when I click a button on the second view controller but when I when I type in the variable name it doesn't show up in the second view controller?
Can somebody explain what I may be doing wrong as I thought the variables were public and globally accessible throughout my app but I'm struggling to figure out what I'm doing wrong.
Here is some of my code:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var timer = Timer()
var softTime = 180
var mediumTime = 300
var hardTime = 600
var chosenTime = 0
I want softTime, mediumTime & hardTime to be changed from the button in the next view controller:
import UIKit
class SettingsViewController: UIViewController {
#IBOutlet weak var softLabel: UILabel!
#IBOutlet weak var softSliderValue: UISlider!
#IBAction func softSlider(_ sender: Any) {
let currentValue = Int(softSliderValue.value)
softLabel.text = "\(currentValue)"
}
#IBOutlet weak var mediumLabel: UILabel!
#IBOutlet weak var mediumSliderValue: UISlider!
#IBAction func mediumSlider(_ sender: Any) {
let currentValue = Int(mediumSliderValue.value)
mediumLabel.text = "\(currentValue)"
}
#IBOutlet weak var hardLabel: UILabel!
#IBOutlet weak var hardSliderValue: UISlider!
#IBAction func hardSlider(_ sender: Any) {
let currentValue = Int(hardSliderValue.value)
hardLabel.text = "\(currentValue)"
}
#IBAction func setTimesButton(_ sender: Any) {
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
//in Second VC
protocol PassDataDelegte: class {
func your method(first: String, second: String, third: String)
}
weak var delegate: PassDataDelegte?
func youction button() {
delegate?.yourmethod(first, timeString: second, third: date)
}
// in First VC
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "DeadlineSegue" {
let dvc = segue.destinationViewController as! YourSecondViewController
dvc.delegate = self
}
}
extension YourFirstViewController: PassDataDelegte {
func sendDateTime((first: String, second: String, third: String) {
print(first)
print(second)
print(third)
}
How can I change the label text to textfield text?
This source code change the label text to textfield text which are in the same class, but I want to change the label in different class.
label is in the ViewController.swift and textfield is in the ProfileViewController.swift
This is the source code:
ViewController.swift
import UIKit
import Social
class ViewController: UIViewController, SideBarDelegate {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var hedgeImage: UIImageView!
#IBOutlet weak var hideView: UIView!
var sideBar:SideBar = SideBar()
override func viewDidLoad() {
}
ProfileViewController.swift
class ProfileViewController: UIViewController {
#IBOutlet weak var ouput: UILabel!
#IBOutlet weak var name: UITextField!
#IBAction func nameChange(sender: AnyObject) {
ouput.text = name.text
}
}
One of the many ways to do this: You can add an observer to textField and update a variable that holds the name text which then you can send to the new vc in prepare for segue. Here is a sample
class ViewController: UIViewController {
var nameRecieved:String?
#IBOutlet weak var name: UILabel!{
didSet{
if nameRecieved != nil { name.text = nameRecieved }
}
}
}
class ProfileViewController: UIViewController, UITextFieldDelegate {
var nameHolder:String?
#IBOutlet weak var name: UITextField! { didSet{ name.delegate = self } }
//notification
var nameTextFieldObserver: NSObjectProtocol?
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
let center = NSNotificationCenter.defaultCenter()
let q = NSOperationQueue.mainQueue()
nameTextFieldObserver = center.addObserverForName(UITextFieldTextDidChangeNotification, object: name, queue: q){
notification in
self.nameHolder = self.name.text
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if nameTextFieldObserver != nil { NSNotificationCenter.defaultCenter().removeObserver(nameTextFieldObserver!) }
}
//Here you can pass the value of nameHolder to the other vc's var nameRecieved in your prepare for segue
}
You need to catch hold on to your ViewController object and pass the values. Something like this:
#IBAction func nameChange() {
ouput.text = name.text
// given both your views have a same parent
// and this view is the first child
let myViewController = parentViewController!.childViewControllers[1]
myViewController.name.text = name.text
myViewController.printLabelText()
}