swift - How sort alphabetically annotations array - swift

My project is a map with a lot of annotations points, and user could look for a specific annotation thanks to a pickerView. All is fine except the list of all annotations points seems randomly displayed. I would like to sort the annotations alphabetically.
Here s my current working code :
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return self.mapView.annotations[row].title ?? "No title"
}
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
self.mapView.selectAnnotation(self.mapView.annotations[row], animated: true)
}
I ve tried to implement this, but without any success...
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
let sortedNames = self.mapView.annotations.sorted(by: {$0.title < $1.title})
return sortedNames[row].title ?? "No title"
}
I ve got this error:
Cannot convert value of type 'String??' to expected argument type
'UIContentSizeCategory'
Any hint would be greatly appreciated.

I'm aware this question is a bit old to answer but for anyone else having the issue the problem is that the String can not be optional. The fix it to either provide a default value or force unwrap it. For example this would be one solution to the question:
let sortedNames = self.mapView.annotations.sorted(by: { ($0.title ?? "") < ($1.title ?? "") }))
return sortedNames[row].title ?? "No title"

I've just had exactly this error when trying to sort an array of a different class by a string property. The problem appears to be that the property you are sorting by is optional. Using a non-optional property works as expected, using an optional property gives the somewhat bizarre 'UIContentSizeCategory' error.
Something like this should do what you need:
let sorted = self.mapView.annotations { (a1, a2) -> Bool in
if let s1 = a1.title {
if let s2 = a2.title {
return s1 > s2
}
}
return false
}

Related

Populating UIPickerview values from CoreData in Swift

I am trying to populate a UIPicker with data that is stored in coreData. they way i have gone about this is i have set up a global variable array and when the screen loads a fetch request is sent to core data which populates the global array. The UIPicker then reads this global array and populates itself with its array of strings.
the problem is that the UIPicker populates fine the first time i load it, but then the second time i get the original entries repeated, and the 3rd time and 4th etc...
global array:
var savedWorkoutNamesPulled = [String]()
UIPicker set up:
//needed picker function (number of columns in picker view)
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
//needed picker function (number of rows in pickr view)
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
savedWorkoutNamesPulled.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
//setting exercisesInSelectedWorkout(exercise names within workout) to the elements of the uipicker
let row = savedWorkoutNamesPulled[row]
return row
}
Calling coredata function:
override func viewDidAppear(_ animated: Bool) {
//calling function that deals show picker
showUiPicker()
//going into core data swift file and calling a function (this function sets global array to fill workout names into picker view)
print("your workouts are as follows")
CoreDataManager.sharedInstance.retrieveWorkoutDataFromCoreData()
}
The core data function that appends values to global array:
func retrieveWorkoutDataFromCoreData() -> [Contact]{
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "ContactsData")
let result = try? context.fetch(fetchRequest)
var contacts = [Contact]()
for data in result as! [NSManagedObject]{
guard let id = data.value(forKey: "id") as? String else {continue}
guard let fullName = data.value(forKey: "fullName") as? String else {continue}
guard let excercise = data.value(forKey: "excersizes") as? [Exercise] else {continue}
var contact = Contact(id: id, fullname: fullName, exercises: excercise)
contact.id = id
contacts.append(contact)
print(fullName)
print(id)
savedWorkoutNamesPulled.append(fullName)
}
return contacts
}
I was able to fix it by just by setting the array to nothing when the view was dismissed.
override func viewDidDisappear(_ animated: Bool) {
savedWorkoutNamesPulled = []
}

How to add a special character in a UIPicker view of integers

Still Learning swift
What Im trying to do is add a "°C" and "°F"
after an integer, I have a created and array of ints and gave them a specific range
that should be in the pickerView, I got the values to display Im just struggling with how I could get that "special char " to display after the integer
I was thinking of maybe creating a for loop and load in the the values like that and append the "°C" and "°F" using the unicode scalar.
I was wondering if anyone has any recommendations of how i could get this done ?
class tempConversionTabViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {
var celsius: [Int] = []
var fahrenheitTemps: [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
fahrenheitTemps += -129...134
celsius += -90...57
// for fahrenheitTemps in -129...134{
// tempPicker.append
//}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
public func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
switch
segmentControl.selectedSegmentIndex{
case 0:
return fahrenheitTemps.count
default:
return celsius.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int , forComponent component: Int) -> String?{
switch segmentControl.selectedSegmentIndex {
case 0:
var selected = fahrenheitTemps[tempPicker.selectedRow(inComponent: 0)]
selected = (selected - 32) * 5/9
convertedLabel.text = String("\(selected) \u{2103}")
let myString = fahrenheitTemps.map { String($0)}
return myString[row]
default:
var selected = celsius[tempPicker.selectedRow(inComponent: 0)]
selected = (selected * 9/5) + 32
convertedLabel.text = String("\(selected) \u{2109}")
let myString = celsius.map { String($0)}
return myString[row]
}
}
Image of how I want it to display
Just use string concatenation to add the character:
Change:
return myString[row]
to:
return myString[row] + "\u{2109}"

Get list of countries from AVSpeechSynthesisVoice

I'm trying to get the Region Code found in AVSpeechSynthesisVoice instead of e.g: en-GB.
The output I'm aiming for is as follow
This is my current code, while it works, I feel there must be a more elegant solution and from what I read, split by - could product errors for some languages
let speechVoices = AVSpeechSynthesisVoice.speechVoices()
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
let language = Locale.current.localizedString(forLanguageCode: speechVoices[row].language)!
let languageCode = speechVoices[row].language
var regionCodeArray = languageCode.split(separator: "-") // FIXME: buggy may break
let regionCode = regionCodeArray.removeLast()
// Must be a more elegant way to get RegionCode
let country = Locale.current.localizedString(forRegionCode: String(regionCode))
return "\(language) (\(country ?? ""))"
}
Thanks!
So I thought of another alternative that doesn't require splitting and this is what I got, but I welcome alternative answers or perhaps a comment on my code as I am learning and looking to improve
let speechVoices = AVSpeechSynthesisVoice.speechVoices()
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
let language = Locale.current.localizedString(forLanguageCode: speechVoices[row].language)!
let languageCode = speechVoices[row].language
var regionCode:String = ""
for region in Locale.isoRegionCodes {
// Test if provided region codes has voices or not
if languageCode.contains(region) {
regionCode = region
}
}
let country = Locale.current.localizedString(forRegionCode: String(regionCode))
return "\(language) (\(country ?? ""))"
}

Accessing information from another viewController

I am new to swift and I am trying to repopulate a pickerview using an array of names from another class. I have this class Notes that creates notes and each note has a name/title, I am trying to access those names/title and put them in pickerview, can anyone help me.
import UIKit
var allNotes: [Note] = []
var currentNoteindex: Int = -1
var noteTable: UITableView?
let kAllNotes:String = "notes"
class Note: NSObject
{
var date:String
var note:String
var name:String
override init()
{
date = NSDate().description
name = ""
note = ""
}
func dictionary() -> NSDictionary
{
return ["note": note, "date": date, "name": name]
}
I have two different pickerview and one works it's just the one with the names doesn't work.
override func viewDidLoad()
{
super.viewDidLoad()
fileNamePicker.dataSource = self
fileNamePicker.delegate = self
gradePicker.dataSource = self
gradePicker.delegate = self
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int
{
if pickerView == gradePicker
{
return grades.count
}
else
{
return allNotes.count
}
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String?
{
if pickerView == gradePicker
{
return grades[row]
}
else
{
//This is where the Problem is, but I don't know how to fix it.
let nameFiles = allNotes[currentNoteindex].name
return nameFiles[row]
}
}
func numberOfComponents(in pickerView: UIPickerView) -> Int
{
return 1
}
nameFiles is accessing a name from a note.
nameFiles[row] doesn't work because nameFiles is not an array.
If you want to return a string, simply do return nameFiles. Check first to make sure that nameFiles actually has a value, though!
Looks like your allNotes array is empty. You have initilaize but does not seems to append the object. Create initiliaze method inside Note class
init(_ date: String, note: String, name: String) {
self.date = date
self.note = note
self.name = name
}
In your viewcontroller class try appending like this. Now below you can access inside picker view method:-
//You can append by doinf iteration based on your data
allNotes.append(Note(date: "value1", note: "Value", name: "name"))

Issue saving PFobjects into an array when using pickerView

i'm relatively new to Swift. I've encountered an issue when using PFQuery in pickerView.
I'm trying to implement a 2 component pickerView as demonstrated below:
Component 0: Component 1
"A": "Altivo", "Altrez"
"B": "Beverly", "Bijou"
Choosing "A" from Component 0 will show "Altivo", "Altrez" in Component 1
The values from Component 1 are queried from Parse by using the value from Component 0
Here's my code:
var condoNameList: [String] = [String]()
var condoPicker = UIPickerView()
var condoAlphabet: [String] = [String]()
private let prefixComponent = 0
private let condoNameComponent = 1
override func viewDidLoad() {
super.viewDidLoad()
condoAlphabet = ["A", "B"]
}
//Start: For condoName picker
func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
return 2
}
func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
if component == prefixComponent{
return condoAlphabet.count
}else {
return self.condoNameList.count
}
}
func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
if component == prefixComponent {
condoNameList.removeAll()
let query = PFQuery(className: "condodirectory")
let selectedalphabet: String = condoAlphabet[row] as String!
query.whereKey("condoName", hasPrefix: selectedalphabet)
query.findObjectsInBackgroundWithBlock{
(objects:[PFObject]?, error:NSError?)->Void in
if error == nil{
for object in objects!{
//print(object)
let condoName:String = object["condoName"] as! String
self.condoNameList.append(condoName)
}
}
//print("condo Name List is \(self.condoNameList)") //Position 1
}
print("condo Name List is \(self.condoNameList)") //Position 2
condoPicker.reloadComponent(condoNameComponent)
condoPicker.selectRow(0, inComponent: condoNameComponent, animated: true)
}
}
func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
if component == prefixComponent{
return condoAlphabet[row]
}else {
return self.condoNameList[row]
}
}
The issue is at Position 1, the print function is able to print out the condoNameList but at Position 2 it prints an empty array. As a result, the list for Component 1 is not showing up in the PickerView.
Anyone knows why?
Thanks in advance for the help.
I managed to solve the problem from another thread by using the didset{} method.
var condoNameList: [String] = [] {
didSet {
self.condoNameListTemp = condoNameList
condoName.inputView = condoPicker
condoPicker.reloadAllComponents()
}
}