Converting from UITextField to Int failure - string

I cannot convert the UITextField to an Int, although I have taken a look at the instructions on the internet. I'm a beginner with Swift 2. Can anyone help?
import UIKit
class ViewController: UIViewController {
#IBOutlet var age: UITextField!
#IBOutlet var resultLabel: UILabel!
#IBAction func findAge(_ sender: AnyObject) {
// Changed "enteredAge = age" to "enteredAge = age!"
var age = Int = Int(age.text)
var enteredAge = Int(age)
if enteredAge != nil {
var catYears = enteredAge! * 7
resultLabel.text = "Your cat is \(catYears) in cat years"
} else {
resultLabel.text = "Please enter a number in the box"
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Entered age use age.text again as in age variable

As I see in your code you are redeclaring the age textfield , I am editing you IBAction . I have not run this code , but I think It will work for you . Just copy paste in your code any check it .
#IBAction func findAge(_ sender: AnyObject) {
var ageToInt = Int(self.age.text!)!
if ageToInt != nil {
var catYears = ageToInt! * 7
resultLabel.text = "Your cat is \(catYears) in cat years"
} else {
resultLabel.text = "Please enter a number in the box"
}
}
Good luck!

Related

Swift 4 - How do I test for TextView content did change?

Swift 4, iOS 11 - I have a UITextView that is pre-populated with text but I want users to be able to save any changes they make to the content there. I also have a Save button in the navigation bar and I would like to disable it until the user actually changes the text in the TextView.
I know how to test for empty but I don't know how to test for when the text has been edited. How do I modify the following to test for changes to the content of TextView?
#IBAction func textEditingChanged(_ sender: UITextView) {
updateSaveButtonState()
}
func updateSaveButtonState() {
let descriptionText = descriptionTextView.text ?? ""
saveButton.isEnabled = !descriptionText.isEmpty
}
We'll to use it a dynamic way and not only in single place, i tried to make it easier to implement around the whole app, subclassing the UITextView is one of the only ways we got here #holex has suggested isEdited boolean flag and it gave me an idea, Thanks to that.
Here is the steps to implement it:
First of all set the defaultText of the textView and set the target of the method that will be called when the textView will be edited, so you can customize what ever you want.
#IBOutlet weak var saveButton: UIBarButtonItem!
#IBOutlet weak var textView: SBTextView!{
didSet{
textView.defaultText = "Hello"
textView.setTarget = (selector:#selector(self.updateSaveButtonState),target:self)
}
}
Lets say you'll setup the saveButton in viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
// setup save button action
saveButton.action = #selector(saveAction(_:))
saveButton.target = self
self.updateSaveButtonState()
}
And last is your save action and the selector to update the view using isEdited flag.
//MARK:- Actions
#objc private func updateSaveButtonState(){
// has not been changed keep save button disabled
if self.textView.isEdited == false{
self.saveButton.isEnabled = false
self.saveButton.tintColor = .gray
}else {
// text has been changed enable save button
self.saveButton.isEnabled = true
self.saveButton.tintColor = nil // will reset the color to default
}
}
#objc private func saveAction(_ saveButton:UIBarButtonItem){
self.textView.updateDefaultText()
}
TextView Custom Class:
//
// SBTextView.swift
//
//
// Created by Saad Albasha on 11/17/17.
// Copyright © 2017 AaoIi. All rights reserved.
//
import UIKit
class SBTextView: UITextView,UITextViewDelegate {
var isEdited = false
private var selector : Selector?
private var target : UIViewController?
var setTarget: (selector:Selector?,target:UIViewController?) {
get{
return (selector,target)
}
set(newVal) {
selector = newVal.0
target = newVal.1
}
}
var textViewDefaultText = ""
var defaultText: String {
get {
return textViewDefaultText
}
set(newVal) {
textViewDefaultText = newVal
self.text = newVal
self.isEdited = false
}
}
//MARK:- Life Cycle
override init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
self.setupTextview()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setupTextview()
}
private func setupTextview(){
// setup textview
self.text = textViewDefaultText
self.delegate = self
}
func updateDefaultText(){
self.defaultText = self.text!
// update save button state
target!.perform(self.selector, with: nil, with: nil)
}
//MARK:- Delegate
internal func textViewDidChange(_ textView: UITextView) {
if textViewDefaultText != textView.text! {
isEdited = true
}else {
isEdited = false
}
// update save button state
target!.perform(self.selector, with: nil, with: nil)
}
}
I hope this helps.

How do I save data using NSKeyedArchiver?

I am very close to finishing my first iOS App using Swift 4 and iOS 11.
The app has a list displayed in a table view controller and a detail view with a UITextView object that is editable. My goal is for the user to be able to make edits to the content in the UITextView and save those changes using NSKeyedArchiver.
I have the list view complete and the detail view connected. You can make edits but they do not save.
I have confirmed that the entry does save to memory that persists beyond the session, but the edits do not save.
Reviews of documentation and working through multiple tutorials have not provided the insights needed. I have attached a screen shot to show the interface of the detail view and here is the code from the detail view controller where the save button triggers the Save action:
import UIKit
import os.log
class ViewController: UIViewController, UINavigationControllerDelegate, UITextViewDelegate {
var season: Season?
//MARK: Properties
#IBOutlet weak var seasonDetail: UITextView!
#IBAction func saveButton(_ sender: UIBarButtonItem) {
if let selectedDetail = seasonDetail.text {
seasonDetail.text = selectedDetail
} else {
print("failed to save changes.")
}
saveChanges()
print("Save button clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
title = season?.name
seasonDetail.text = season?.detail
seasonDetail.delegate=self
}
override func viewWillDisappear(_ animated: Bool) {
season?.detail = (seasonDetail?.text)!
}
func textViewDidEndEditing(_ textView: UITextView) {
seasonDetail.text = season?.detail
}
//MARK: UITextViewdDelegate
func textViewShouldReturn(_ textView: UITextView) -> Bool {
textView.resignFirstResponder()
return true
}
func saveChanges() {
print("Saving items to: \(Season.ArchiveURL)")
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(season as Any, toFile: Season.ArchiveURL.path)
if isSuccessfulSave {
os_log("Season sucessfully saved.", log: OSLog.default, type: .debug)
} else {
os_log("Failed to save season.", log: OSLog.default, type: .debug)
}
}
}
Here is the code from the data model class:
import UIKit
import os.log
class Season: NSObject, NSCoding {
//MARK: Properties
var name: String
var detail: String
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("season")
//MARK: Types
struct PropertyKey {
static let name = "name"
static let detail = "detail"
}
//MARK: Initialization
init?(name: String, detail: String) {
guard !name.isEmpty else {
return nil
}
guard !detail.isEmpty else {
return nil
}
// Initialize stored properties
self.name = name
self.detail = detail
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(detail, forKey: PropertyKey.detail)
}
required convenience init?(coder aDecoder: NSCoder) {
// the name is required. If we cannnot get a name string, the initializer should fail.
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String
else {
os_log("Unable to decode the name for a Season object.", log: OSLog.default, type: .debug)
return nil
}
let detail = aDecoder.decodeObject(forKey: PropertyKey.detail)
self.init(name: name, detail: detail as! String)
}
}
My goal is to understand what is missing with my code and know how to persist all the data, including the edits. I would appreciate any direction that would help.
Please check :
class ViewController: UIViewController, UINavigationControllerDelegate, UITextViewDelegate {
var season: Season?
#IBOutlet weak var seasonDetail: UITextView!
#IBAction func saveButton(_ sender: UIBarButtonItem) {
if let selectedDetail = seasonDetail.text {
season?.detail = selectedDetail // this is the line
} else {
print("failed to save changes.")
}
saveChanges()
print("Save button clicked")
}
override func viewDidLoad() {
super.viewDidLoad()
if season == nil {
season = Season(name: "Season Name", detail: "Season Details")
}
title = season?.name
seasonDetail.text = season?.detail
seasonDetail.delegate=self
}
override func viewWillDisappear(_ animated: Bool) {
season?.detail = (seasonDetail?.text)!
}
func textViewDidEndEditing(_ textView: UITextView) {
season?.detail = seasonDetail.text
}
//MARK: UITextViewdDelegate
func textViewShouldReturn(_ textView: UITextView) -> Bool {
textView.resignFirstResponder()
return true
}
func saveChanges() {
print("Saving items to: \(Season.ArchiveURL)")
let isSuccessfulSave = NSKeyedArchiver.archiveRootObject(season as Any, toFile: Season.ArchiveURL.path)
if isSuccessfulSave {
os_log("Season sucessfully saved.", log: OSLog.default, type: .debug)
} else {
os_log("Failed to save season.", log: OSLog.default, type: .debug)
}
}
}

Multithreading in Swift 3 with GCD

I'm working on a webservice based app and I've come to a crashing hault due to sending requests too quickly to the webservice. I simply can not getting GCD working in Swift 3 and I'm scratching my head. I've decided to dumb it down and just try loading 4 web images to a web view in order. Based on everything I'm seeing online the following code should work, but it is still freezing the UI until all four images load. What am I doing wrong?
import UIKit
let imageURLs = ["http://www.planetware.com/photos-large/F/france-paris-eiffel-tower.jpg", "http://adriatic-lines.com/wp-content/uploads/2015/04/canal-of-Venice.jpg", "http://hd-wall-papers.com/images/wallpapers/hi-resolution-pictures/hi-resolution-pictures-5.jpg", "http://hd-wall-papers.com/images/wallpapers/hi-resolution-pictures/hi-resolution-pictures-1.jpg"]
class Downloader {
class func downloadImageWithURL(_ url:String) -> UIImage! {
let data = try? Data(contentsOf: URL(string: url)!)
return UIImage(data: data!)
}
}
class ViewController: UIViewController {
#IBOutlet weak var imageView1: UIImageView!
#IBOutlet weak var imageView2: UIImageView!
#IBOutlet weak var imageView3: UIImageView!
#IBOutlet weak var imageView4: UIImageView!
#IBOutlet weak var sliderValueLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func didClickOnStart(_ sender: AnyObject) {
let serialQueue = DispatchQueue(label: "syncQueue")
serialQueue.sync{
let img1 = Downloader.downloadImageWithURL(imageURLs[0])
DispatchQueue.main.async(execute: {
self.imageView1.image = img1
})
}
serialQueue.sync{
let img2 = Downloader.downloadImageWithURL(imageURLs[1])
DispatchQueue.main.async(execute: {
self.imageView2.image = img2
})
}
serialQueue.sync{
let img3 = Downloader.downloadImageWithURL(imageURLs[2])
DispatchQueue.main.async(execute: {
self.imageView3.image = img3
})
}
serialQueue.sync{
let img4 = Downloader.downloadImageWithURL(imageURLs[3])
DispatchQueue.main.async(execute: {
self.imageView4.image = img4
})
}
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
self.sliderValueLabel.text = "\(sender.value * 100.0)"
}
}
freezing the UI
Because you are calling serialQueue.sync. You almost never want to call sync, and in this case you certainly don't. Use async instead.

Different info for different pin annotations

I have two different pins placed on my mapview. I have an info button on each. The info buttons will segue to the a UIViewController that has a Image view (to hold a picture of the place) and a Text label ( To hold info about the place).
My problem is how can I generate the Info and picture depending on which pin annotation button was selected. The last function is the one used in order to segue to the info view controller.
class GetToTheStart: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
//map view outlet
#IBOutlet weak var mapView: MKMapView!
//defining use of location manager
let myLocMgr = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
//setting up location request
myLocMgr.desiredAccuracy = kCLLocationAccuracyBest
myLocMgr.requestWhenInUseAuthorization()
myLocMgr.startUpdatingLocation()
myLocMgr.delegate = self
mapView.delegate = self
// coordinates of desired locations for pins
var zoo1 = CLLocationCoordinate2DMake(53.347439, -6.291820)
var town1 = CLLocationCoordinate2DMake(53.347247, -6.290865)
//setting up pin 1 annotation (the zoo)
var zoopin = MKPointAnnotation()
zoopin.coordinate = zoo1
zoopin.title = "Dublin Zoo"
zoopin.subtitle = "This this the zoo"
mapView.addAnnotation(zoopin)
//setting up pin 2 annotation (the town)
var townpin = MKPointAnnotation()
townpin.coordinate = zoo1
townpin.title = "Dublin town"
townpin.subtitle = "This this the town"
mapView.addAnnotation(townpin)
}
//setting up Pin callout button for segue
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if annotation is MKUserLocation {
}
let reuseIdentifier = "pin"
var pin = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseIdentifier) as? MKPinAnnotationView
if pin == nil {
pin = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseIdentifier)
pin!.pinColor = .Red
pin!.canShowCallout = true
pin!.rightCalloutAccessoryView = UIButton(type: .DetailDisclosure)
} else {
pin!.annotation = annotation
}
return pin
}
//performing segue from info button to infoViewController
func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, calloutAccessoryControlTapped control: UIControl) {
performSegueWithIdentifier("info", sender: view)
}
For this you need to override below method. Here we will get the annotationView which will trigger the segue.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "info") {
if let annotation = sender as? MKAnnotationView {
let detailViewController = segue.destinationViewController as! DetailViewController
detailViewController.titleText = annotation.annotation?.title ?? ""
detailViewController.detaileText = annotation.annotation?.subtitle ?? ""
}
}
}
And in the detailViewController is same as your infoViewController and here I have two labels and for that I have two public variables. This is just to avoid error because at this point we don't have the label objects.
Here is the code for my DetailViewController.
import UIKit
class DetailViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var detailLabel: UILabel!
var titleText: String? { didSet { updateUI() } }
var detaileText: String? { didSet { updateUI() } }
override func viewDidLoad() {
super.viewDidLoad()
updateUI()
}
private func updateUI() {
self.titleLabel?.text = self.titleText
self.detailLabel?.text = self.detaileText
}
}

How do you show a blue dot instead of a Pin when showing current location in mapview?

How do you show a blue dot instead of a Pin when showing current location in map view? at the moment the code illustrates a red pin that shows the users current location as the user moves around. How can i convert this to the blue dot that apple use?
import UIKit
import MapKit
class ViewController: UIViewController,CLLocationManagerDelegate {
#IBOutlet weak var myMapView: MKMapView!
let myLocMgr = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
myLocMgr.desiredAccuracy = kCLLocationAccuracyBest
myLocMgr.requestWhenInUseAuthorization()
myLocMgr.startUpdatingLocation()
myLocMgr.delegate = self
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// get most recient coordinate
let myCoor = locations[locations.count - 1]
//get lat & long
let myLat = myCoor.coordinate.latitude
let myLong = myCoor.coordinate.longitude
let myCoor2D = CLLocationCoordinate2D(latitude: myLat, longitude: myLong)
//set span
let myLatDelta = 0.05
let myLongDelta = 0.05
let mySpan = MKCoordinateSpan(latitudeDelta: myLatDelta, longitudeDelta: myLongDelta)
let myRegion = MKCoordinateRegion(center: myCoor2D, span: mySpan)
//center map at this region
myMapView.setRegion(myRegion, animated: true)
//add anotation
let myAnno = MKPointAnnotation()
myAnno.coordinate = myCoor2D
myMapView.addAnnotation(myAnno)
}
#IBAction func stop(sender: AnyObject) {
myLocMgr.stopUpdatingLocation()
}
#IBAction func resume(sender: AnyObject) {
myLocMgr.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
self.myMapView.showsUserLocation = true
showsUserLocation is what you need. It's MKMapView property set it in viewDidLoad or using IB (if possible). You don't need to do any extra stuff in LocationManager's delegate didUpdateLocations, just set it the MKMapView will do the rest of the stuff

Resources