I haver been working with Swift a lot lately and as such, I have come across a few little problems or minor inconveniences that I have managed to solve. In this post, I will share some of those things that I came across. To be specific, I will give some Swift tips: Reverse Geocoding (CLGeoCoder)  and

  1. how to get the correct location address
  2. a little on String manipulation in Swift.

p.s. This came about because I am building some new products for My Day To-Do, where I spend a lot of time working with iOS/Swift.  In addition to Swift/iOS, I also spend a lot of time working with Ionic and AngularJS but more on that later.

Swift tips: Reverse geocoding & accuracy

This is something I came across a lot when building our photo and location app, “Snap! I Was There”. The problem is, when you try to make a photo memory in that app, it starts tracking your location. It does that via the CoreLocation.LocationManager, gets your position (Lat and Lon) and reverse GeoCodes the coordinates using CLGeocoder and display the address (actual name) on screen. The problem was, every now and then, it would show some random address, something that doesn’t make any sense. Do note the key words are every now and then, so it was just very inconsistent.

Solution

Unfortunately, given the amount of responsibilities on my shoulders in this startup, I had little time to fully investigate this and find out the cause of this. My guess was, maybe it’s just Apple Maps, which aren’t as good as Google Maps? Maybe it’s a network connection issue? or something else? I simply couldn’t afford to spend any more time on this, hence I came up with a workaround.

Collecting values

As you may have guessed by now, the algorithm for is very simple. Instead of immediately displaying the location string , we observe it for some time. We already know that, we get the incorrect location string at random, so the code to reverseGeocode is not consistently wrong, so let’s just wait till we get the right string. In practice, we keep count of how often did we receive a particular location string and after X seconds we find the string with the maximum occurrences and display it. Anyway below is the Swift code for it,

var addressDict = [String: Int]()
let ADDRESS_THRESHOLD = 10 //an arbitrary number, could be anything
var count = 2 //an arbitrary no too
func updateLocationAddress() {
    if let address = geoLocationHelper.address?.getDisplayAddress() {
        addressDict[address, default: 0] += 1
    }
    if count == ADDRESS_THRESHOLD {
        let maxElem = addressDict.max{ a, b in a.value < b.value }
        locationLbl.text = maxElem?.key
        addressDict = [String: Int]()
        count = 0
    }
}

fyi: i wrote the above code to explain the algorithm as clearly as I could, coding wise, I know there are more efficient ways to accomplish the above.

Did you notice our method to get the max occurring in a dictionary?

let maxElem = addressDict.max{ a, b in a.value < b.value }

Coming from a Java background this is one of the things that I appreciate about Swift i.e. the code isn’t overly verbose.

Ok in case you are wondering, what’s the code to reverse GeoCode location coordinates, here’s what it could look like

func reverseGeocoding(_ lat: Double, _ lon: Double, completionHandler: @escaping (_ name: String?, _ locality:String?, _ country: String?,_ sublocality: String?) -> ()) {
    let location = CLLocation(latitude: lat, longitude: lon)
    CLGeocoder().reverseGeocodeLocation(location) {
        (placemarks, error) in
        if error == nil {
            completionHandler(nil, nil, nil, nil)
        }
        let result = self.processPlacemarks(placemarks)
        completionHandler(result.name, result.locality, result.country, result.sublocality)
    }
}

String manipulation

I will re-iterate what I said before, “coming from a Java background”, String manipulation in Swift was a little challenging for me to understand at first. I was used to just using integer values to replace, substring values in a string by specifying an integer. In Swift, however, it was all about String.Index and initially it was a little confusing, I kept thinking what’s a String.Index? is it just another way of representing an integer value? Then I decided to actually have a read of how strings are represented in Swift, it’s all about Grapheme clusters.

A String and Character type in String are fully Unicode compliant, the reason for mentioning this will become clear as you read further.

We can represent letters of different languages, Mathematical symbols or more importantly, even EMOJI. Ok, to be precise, as the docs at docs.swift.org specify, each character in Swift represents a single extended grapheme cluster which (cluster) is a collection of Unicode scalars. Ok what’s a Grapheme? It’s the smallest unit of a writing system, and as the name implies a Grapheme cluster is a collection of them, therefore a collection of Unicode scalars. If you need a deep dive into character encoding, I am sure you are better off doing a Google/Bing search for it, than anything I would write here.

Now, let’s focus on String based problem that I wanted to solve in Swift.

Get updates?

Delete the last word in a sentence

The name is pretty self-explanatory and so is the code for it,

func deleteLastWord() -> Bool {
    let text = "some text"
    var wordsRemoved = [String]()
    if let spaceIdx = text.lastIndex(where: {$0 == " "}) {
        let startPos = text.index(after: spaceIdx)
        let endPos = text.index(before: text.endIndex)
        let removedText = String(text[startPos...endPos])
        wordsRemoved.append(removedText)
    } 
}

Do note that startPos and endPos variables do not contain an Int values instead, they have the String.Index. If you are going to be working with Swift, chances are you will be doing a lot of String manipulation, so get used to String.index, you will be using it a lot when doing any string manipulation in Swift. Anyway, each line of code is self explanatory in the above piece of code, the only different part is how we actually remove the last word from the string i.e.

text[startPos...endPos])

it’s simple, all we do is tell Swift, return all the characters except the ones from the start and end position. See,... means from start <= end, and if we had ..< then from start up to less than end.

Get updates?

Summary

As I mentioned earlier, I will keep this short, so that’s all for now, I will blog more as I get to know more about the in’s and out’s of the platform. Swift is a fun language to work with and to me, working with it is somewhat relaxing. Relaxing because, the language is  less verbose and it has great documentation. Such things make a developer’s life easier. Anyway what I know for sure, mostly…. is that my next blogpost would be about a Hybrid app with Ionic and Firebase authentication, so stay tuned…

Get updates?

As usual, if you find any of my posts useful support me by  buying or even trying one of my apps on the App Store. 

https://mydaytodo.com/apps/

Also, if you can leave a review on the App Store or Google Play Store, that would help too.

[appbox googleplay com.mydaytodo.simplenotes]

Categories: iOSSwift

0 Comments

Leave a Reply

Avatar placeholder
Verified by MonsterInsights