How to use UISegmentedControl in guard together with textfields - swift

I am currently facing a problem where I want to use guards to enable a button if desired information are filled out.
After reading into the guard mechanism one thing is unclear for me.
How do i combine UITextFields with UISegmentedControls so that both have to be filled out/selected in order to activate the button.
#objc func editingChanged(_ textField:UITextField, sgmntControl: UISegmentedControl) {
if textField.text?.count == 1 {
if textField.text?.first == " " {
textField.text = ""
return
}
}
guard
let name = tbxName.text, !name.isEmpty,
let firstName = tbxFirstname.text, !firstName.isEmpty,
let phoneNr = tbxPhoneNr.text, !phoneNr.isEmpty,
let birthDate = tbxBirthdate.text, !birthDate.isEmpty,
let gender = sgmntGender, !gender.isSelected,
let street = tbxStreet.text, !street.isEmpty,
let postalCode = tbxPLZ.text, !postalCode.isEmpty,
let city = tbxCity.text, !city.isEmpty,
let country = tbxCountry.text, !country.isEmpty,
let idNumber = tbxIdNo.text, !idNumber.isEmpty,
let valueCheck = sgmntValueCheck, !valueCheck.isSelected,
let drivingSchoolFlyer = sgmntDrivingSchoolFlyer, !drivingSchoolFlyer.isSelected,
let visionTest = sgmntVisionTest, !visionTest.isSelected,
let visionHelp = sgmntVisionHelp, !visionHelp.isSelected
else {
rbbtnSave!.isEnabled = false
return
}
rbbtnSave!.isEnabled = true
}
I am currently not sure if my approach is correct, googling didn't help either.
I thought that it would make sense to use the UISegmentedControl just like the text field, since both are checking for booleans with isSelected and isEmpty.

Related

Eureka Swift - set value of LocationRow

I've got a form where a user can pick from a number of objects that includes co-ordinate data, which I want to load into a LocationRow.
I have tried several different ways to try and set the Location Row value, but it either crashes (unexpectedly found nil while unwrapping an optional Value) or doesn't reload the table with the correct data. i.e. https://i.imgur.com/2XkeHbu.png
My LocationRow eureka code:
$0.rowRight = LocationRow(){
$0.title = "Location"
$0.tag = "location"
if let page = selectedPage {
if let pageLocationLatitude = page.locationLatitude.value,
let pageLocationLongutude = page.locationLongitude.value {
print("testing for row update")
$0.value = CLLocation(latitude: pageLocationLatitude, longitude: pageLocationLongutude)
}
}
}
and the function that is called when I want to update the LocationRow
private func setSelectedPage(pageName : String) {
print("setting location of page: \(pageName)")
if pageName == username {
return
}
selectedPage = userPages?.filter("name == \"\(pageName)\"").first
if let locationLongitude = selectedPage?.locationLongitude.value,
let locationLatitude = selectedPage?.locationLatitude.value {
print("lat and lon: \(locationLatitude) \(locationLongitude)")
/*PURELY FOR TESTING
let titleRow = self.form.rowBy(tag: "title") as! TextRow
titleRow.value = "TEST WORKS OK"
titleRow.updateCell()
PURELY FOR TESTING */
let locationRow = self.form.rowBy(tag: "location") as! LocationRow
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
self.form.rowBy(tag: "location")?.updateCell()
}
self.tableView.reloadData()
}
From your code, I can see that you are putting this location row in a SplitRow:
// rowRight is a property of SplitRow
$0.rowRight = LocationRow(){
Therefore, the form doesn't really know about the location row. It only knows about the split row. You should get the split row using its tag first, then access rowRight.
// use the tag of your split row here!
let splitRow = self.form.rowBy(tag: "splitRow")
as! SplitRow<SomeRow, LocationRow> // replace SomeRow with the type of row on the left of the split row
let locationRow = splitRow.rowRight
locationRow.value = CLLocation(latitude: locationLatitude, longitude: locationLongitude)
locationRow.updateCell()

Building Name using current location

I am trying to get House number using CLLocationManagerDelegate and MKMapViewDelegate but it did not work. By using this i am getting Sub-locality area and sub administrative thoroughfare and sub-through fare but not getting building name.
Please help how to get building name
I have already tried using CLLocationManagerDelegate method reversegeocoder and CLLocationManagerDelegate.
CLGeocoder().reverseGeocodeLocation(location){ (placemark, error) in
let place = placemark?[0]
print(placemark?[0].addressDictionary?[0])
let subloc = place?.subLocality
let city = place?.locality
print("\(subloc!),\(city!),\(place?.administrativeArea)")
print(place?.areasOfInterest?.count)
if let subLocal = place?.subLocality, let cityCustom = place?.locality
{
self.locationname.text = ("\(subLocal),\(cityCustom)")
self.locationname.text = (placemark?[0].addressDictionary?[0]) as? String
self.address = self.locationname.text ?? ""
print(placemark?[0].addressDictionary?[0]) as? String
if let marks = placemark, marks.count > 0 {
let placemark = marks[0]
let postalAddress = placemark.addressDictionary
if let address = postalAddress?.first {
print("\(address)")
}
if let State = placemark.addressDictionary?["State"]{
print("\(State)")
}
if let Street = placemark.addressDictionary?["Street"]{
print("\(Street)")
}
if let Name = placemark.addressDictionary?["Name"]{
print("\(Name)")
}
if let Thoroughfare = placemark.addressDictionary?["Thoroughfare"]{
print("\(Thoroughfare)")
}
if let subThoroughfare = placemark.addressDictionary?["SubThoroughfare"]{
print("\(subThoroughfare)")
}
if let FormattedAddressLines = placemark.addressDictionary?["FormattedAddressLines"]{
print("\(FormattedAddressLines)")
self.locationname.text = (FormattedAddressLines as AnyObject).componentsJoined(by: ",") as? String
self.address = self.locationname.text ?? ""
self.locationname.numberOfLines = 2
self.locationname.sizeToFit()
self.locationname.textAlignment = .center
}
}
}
else
{
self.alertbox(title1: UrlSheet.UrlName.msgTitle, message1: "Location service is disabled on your phone at the moment. Please enable the same before marking the attendance.")
}
self.mapviews.isUserInteractionEnabled = false
manager.stopUpdatingLocation()
}
Expected Result:
DLf-Tower A, Jasola Distric Center,New Delhi
Actual Result: Jasola Distric Center,New Delhi
Visit: https://developer.apple.com/documentation/corelocation/clplacemark For All Supported Placemark by Apple

How to reduce if-condition looping - Swift

I know it sounds crazy, but just curious how I can reduce the if loop iteration for following? I have tried using guard let but stucked at some place.
{
if arenaEventItems == nil || arenaEventItems.count <= 0 {
return
}
if (arenaEventItems.count > 0 && (self.arenaEvents?.monthsDictObjList.count)! > 0){
if (self.tableView != nil){
if let arrVisibleRows = self.tableView.indexPathsForVisibleRows as? [IndexPath]{
if (self.tableView.indexPathsForVisibleRows!.count > 0){
let indexPath : IndexPath = self.tableView.indexPathsForVisibleRows!.first!
if let dict = self.arenaEvents?.monthsDictObjList[indexPath.row] {
if(self.arenaHeaderView != nil) && (dict.count) > 0 {
self.arenaHeaderView?.setMonthTitle(string: (dict.keys.first!))
let selectedMonthTitle = (dict.keys.first!)
for month in (self.arenaEvents?.uniqueMonthOnlyList)! {
if (selectedMonthTitle.contains(month)){
selectedMonthIndex = (self.arenaEvents?.uniqueMonthOnlyList.index(of: month)!)!
break
}
}
}
}
}
}
}
}
}
You can reduce it like that, without any forced unwrapping or nesting:
guard let arenaEventItems = arenaEventItems,
!arenaEventItems.isEmpty,
let arenaEvents = self.arenaEvents,
!arenaEvents.monthsDictObjList.isEmpty,
let arenaHeaderView = self.arenaHeaderView,
let indexPath = self.tableView?.indexPathsForVisibleRows?.first,
let selectedMonthTitle = arenaEvents.monthsDictObjList[indexPath.row].keys.first
else {
return
}
arenaHeaderView.setMonthTitle(string: selectedMonthTitle)
if let monthIndex = arenaEvents.uniqueMonthOnlyList.index(where: { selectedMonthTitle.contains($0) }) {
selectedMonthIndex = monthIndex
}
you replace if ... return with guard !... else return to avoid nesting
you replace .count > 0 with !...isEmpty as best practice
you replace multiple access to self.something? with if let something = self.something to avoid threading issues
you unloop for ... in ... { if (...) { ... } } to .index(where: ...)
You can combine all the conditions in "if" and get something like this:
if let eventItems = arenaEventItems,
eventItems.count > 0,
let events = self.arenaEvents,
!events.monthsDictObjList.isEmpty,
let tableView = self.tableView,
let arrVisibleRows = self.tableView.indexPathsForVisibleRows as? [IndexPath],
!arrVisibleRows.isEmpty,
let indexPath : IndexPath = arrVisibleRows.first,
let dict = events.monthsDictObjList[indexPath.row],
let headerView = self.arenaHeaderView,
!dict.isEmpty {
headerView.setMonthTitle(string: (dict.keys.first!))
let selectedMonthTitle = (dict.keys.first!)
for month in events.uniqueMonthOnlyList! {
if (selectedMonthTitle.contains(month)){
selectedMonthIndex = (events.uniqueMonthOnlyList.index(of: month)!)!
break
}
}
}
You should consider restructuring your code, your code is not readable and incomprehensible for anyone who look at it. Since, you are using Swift, it is really easy to write such code with guard ... else, if ... let
pattern.
Some improvements that you can do on class is have your view non nil ie make them implicitly unwrapped optional, since you will always be connecting them to storyboard.
#IBOutlet var tableView: UITableView!
#IBOutlet var arenaHeaderView: ArenaHeaderView!
Also, you have arrays which can go to nil, why do you want it to be nil. You could simply initialize an empty array and dictionaries. That way you can reduce some more comparison code like so,
arenaEventItems: [String: String] = [:]
With that changes and a bit of refactoring, you could possibly rewrite your code to something like this,
guard !arenaEventItems.isEmpty,
let arenaEvents = arenaEvents,
let indexPath = tableView.indexPathsForVisibleRows?.first,
let dict = arenaEvents.monthsDictObjList[indexPath.row],
let selectedMonthTitle = dict.keys.first
else {
return
}
arenaHeaderView.setMonthTitle(string: selectedMonthTitle)
for month in arenaEvents.uniqueMonthOnlyList where selectedMonthTitle.contains(month) {
if let selectedIndex = arenaEvents.uniqueMonthOnlyList.index(of: month) {
selectedMonthIndex = selectedIndex
break
}
}

How to retrieve phone number from Contacts framework

New to contacts trying to retrieve Mobile Phone number. I have address name email but cannot figure out mobile phone. This is what I got. The portion marked with ** is where I am going wrong.
if let oldContact = self.contactItem {
let store = CNContactStore()
do {
let mykeysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPostalAddressesKey,CNContactImageDataKey, CNContactImageDataAvailableKey,CNContactPhoneNumbersKey]
let contact = try store.unifiedContactWithIdentifier(oldContact.identifier, keysToFetch: mykeysToFetch)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if contact.imageDataAvailable {
if let data = contact.imageData {
self.contactImage.image = UIImage(data: data)
}
}
self.fullName.text = CNContactFormatter().stringFromContact(contact)
self.email.text = contact.emailAddresses.first?.value as? String
self.phoneNumber.text = contact.phoneNumbers.first?.value as? String
**if contact.isKeyAvailable(CNContactPhoneNumbersKey){
if let phoneNum = contact.phoneNumbers.first?.value as? String {
self.phoneNumber.text = phoneNum as String
}
}**
if contact.isKeyAvailable(CNContactPostalAddressesKey) {
if let postalAddress = contact.postalAddresses.first?.value as? CNPostalAddress {
self.address.text = CNPostalAddressFormatter().stringFromPostalAddress(postalAddress)
} else {
self.address.text = "No Address"
}
}
})
} catch {
print(error)
}
}
If you want a list of the mobile phones for a contact, you look at phoneNumbers which is an array of CNLabeledValue, and find those with a label of CNLabelPhoneNumberMobile or CNLabelPhoneNumberiPhone.
For example, you could do something like:
let mobilePhoneLabels = Set<String>(arrayLiteral: CNLabelPhoneNumberMobile, CNLabelPhoneNumberiPhone, "cell", "mobile") // use whatever you want here; you might want to include a few strings like shown here to catch any common custom permutations user may have used
let mobileNumbers = contact.phoneNumbers.filter { mobilePhoneLabels.contains($0.label) && $0.value is CNPhoneNumber }
.map { ($0.value as! CNPhoneNumber).stringValue }
So if you want the first one:
let mobileNumber = mobileNumbers.first ?? "" // or use `if let` syntax
Or if you want a string representation of the list of them:
let mobileNumberString = mobileNumbers.joinWithSeparator(" ; ")
What you do with this array of mobile numbers is up to you, but hopefully this illustrates the basic idea.

swift ? must be followed by a call, member lookup, or subscript

I think I'm looking at some outdated code:
#IBAction func stockLevelDidChange(sender: AnyObject) {
if var currentCell = sender as? UIView {
while (true) {
currentCell = currentCell.superview!;
if let cell = currentCell as? ProductTableCell {
if let id = cell.productId? {
var newStockLevel:Int?;
if let stepper = sender as? UIStepper {
newStockLevel = Int(stepper.value);
}
else if let textfield = sender as? UITextField {
if let newValue = textfield.text.toInt()? {
newStockLevel = newValue;
}
}
if let level = newStockLevel {
products[id].4 = level;
cell.stockStepper.value = Double(level);
cell.stockField.text = String(level);
}
}
break;
}
}
displayStockTotal();
}
}
But in the first line of the function I get " '?' must be followed by a call, member lookup, or subscript" (for the question mark after as)
What does this error mean and how does this code change for Swift 1.2?
Actually the as? are all fine. The problem is this line:
if let id = cell.productId?
Just remove the question mark at the end of that. It makes no sense.
In 1.2, toInt is gone. So,
if let newValue = textfield.text.toInt()?
Should be replaced with:
if let newValue:Int? = Int(textField.text!)
The problem is the if let newValue = textfield.text.toInt()? { .. If toInt() returns an Int? then just get rid of the ? there.