Sunday, 28 April 2019

What good is a Privacy Policy?

A friend recently pointed out the existence of an Israeli app called Shiri (שירי), which allows its users to freely listen a large collection of Israeli songs. Generally speaking, I hesitate to install new apps on my phone on account of the regular abuse of my privacy and security performed by most apps (a phenomenon I had already discussed here). However, out of curiosity, I decided to give this particular app a proper examination.

First, I went to the app's iTunes page in order to check its website out. It is there that I found Shiri's privacy policy, which - to my eyes - seemed quite impressive. Under the assumption of fair use (which I believe I have on my side here, as I am about to critically assess this policy), I will quote some of its more appealing aspects:
The National Library collects only personal information provided by you, willingly [emphasis by yours truly], with active and informed consent granted during your user registration process and\or during your request of services and\or...
The National Library will not transfer your personal information to third parties unless (a) it is required to do so by law, and\or (b) it was required to submit information to an authorized authority according to that authority's request, and\or (c) it was necessary for the provision of the requested services and you approved the transfer of the information to that third party.
Given such a lovely privacy policy, I went out and installed the free app. However, before starting the app for the first time I set up a proxy service in order to capture all the online activities performed by the app.
The next thing I did was start the app. I will emphasise here that I only started the app, did not press anything, and got only as far as its welcome page. However, by then my proxy service already showed the following online connections were made by the Shiri app:

Three usual suspects are immediately noticeable: Google, Facebook, and Apple. Apple can be excused by the fact it is the phone's operating system itself that contacts Apple every time an app is started in order to support Apple's app usage statistics. However, there is no excuse for Facebook nor Google to be there. Not when the above quoted privacy policy says that no personal information of mine will be transferred to third parties (which is exactly what Google and Facebook are, in this particular case).
Even if the inclusion of Facebook and Google was included because "it was necessary for the provision of the requested services", I do not recall having "approved the transfer of the information to that third party"; all I did was start the app for the very first time. It cannot be said that I had willingly provided my consent for my information to be collected!
Further, Google and Facebook were not the only trackers to join the Shiri party; they are just the most famous. As you can see in the above screen shot, we also had, appsflyer, hockeyapp, and crashlytics. Now, it may be argued that these are not your average data harvesting services out there to suck as much information about you (the way Google and Facebook act), but rather services that are there to help the app developer ensure they are providing good service. However, these are still third parties, they are still collecting my information, and I still haven't provided any consent for them to do that. More importantly, in the context of this post, they were never supposed to exist in the first place given Shiri's privacy policy!

Why is it, then, that Shiri is acting this way? Why is Shiri publishing a privacy policy which it then completely ignores?
I strongly suspect there was no ill will on behalf of Shiri here; just good old ignorance. One part of the organisation, with all the good idealism on its side, wrote a marvelous privacy policy; then another part of the organisation (probably with the help of external contractors) went out to develop an app, and that part chose to use SDKs from Google and Facebook. While at it, they chose to use several third party services to help them with the app's development and running. I suspect they did not even bother to read their organisation's own privacy policy.
Who does, these days?

Wednesday, 10 April 2019

Using Multi-Dimensional Arrays in Swift 5

Coming from old school programming, I sort of grew to regard multi dimensional arrays as a given; the stuff one learns at the second programming lesson during one’s early high school career. These days, that does not seem to be the case anymore, to the point of finding myself wasting way more time than I thought I’d need in order to figure how to work it out in Swift 5. This post is therefore here in order to help me solidify my findings, and if - in the process - I’d actually end up helping others, then I have done even better.

First, I will point you to the sources I have found the most helpful. That honour falls unto Paul Hudson for this post, to which I will add I have been finding his posts (and for that matter, his books) very helpful.
My second source of inspiration was this post Multidimensional Arrays in Swift from, which provides some good practical examples.
Feel free to pause and have a look at these two before reading the rest of this post.

On to the main event.
The problem I was facing, which can be generally summed up as “how do I use multi-dimensional arrays in Swift 5”, can be further broken down into the following:
  1. How do I declare a multi dimensional array in Swift 5?
  2. Once declared, how do I even address a particular member in the array’s matrix?
  3. How do I add values into such an array?
  4. In particular, how do all of the above happen when my array is not of a simple type (say, Int or String), but is rather a multi dimensional array of a complex struct that is made its own arrays, booleans, and other complex structures?
  5. How do I manipulate particular (and generally unknown) cells in the array’s matrix, while leaving most of the other cells alone? Specifically, how do I get to do that in Swift, with its prudish (but justifiable) emphasis on declaring and initialising anything and everything?

With that in mind, let’s have a detailed look at the various solutions and compromises I was able to identify. I’m sure experts will have a look and then laugh, but - regardless - this is what I was able to come up with within a reasonable timeframe.
The declaration part is easy. This is how one defines a two dimension array of a struct that I called Cell:
var grid = Cell()

Once declared, accessing a particular “cell” in the matrix is done via:
Where i and j point at the row and column in that array.

Obviously, before accessing grid[i][j] there have to be values there (or Xcode will raise a runtime error), which brings us to the more tricky bits.
I have found that simply asking Xcode to add individual “cells”, say grid[0][0], would not work. I had to append rows to the matrix first!
For example, in a case where I needed a matrix of 10 rows, I needed to do something like this in order to get rid of runtime errors later -
for _ in 0…9 {
            grid.append([Cell(value: 0, providedByUser: false)])
This adds 10 rows and 1 column into my grid, all of which contain data that I could - for now - ignore.
What is worth noting here, however, is the syntax I had to apply in order to append my values. As mentioned, individual cells in my matrix are made of a struct that is more complex than, say, Int; in this particular case, they are made of value (which is an Int) and of providedByUser (which is a boolean).

With this initialisation of the grid now performed, I was finally able to enter the individual values I wanted into specific cells of my grid. However, as per usual Swift standards, I had to do it properly and in order, so I ended up doing it using for loops:
for i in 0…9 {
            for j in 0…9 {
                if j == 0 {
                    grid[i][j] = (Cell(value: 1, providedByUser: true))
                } else {
                    grid[i].append(Cell(value: 1, providedByUser: true))
In the above, do note the different way of setting values when dealing with the first column of a row as opposed to when dealing with the rest of the row. That difference is a side effect of the fact I had already created that first column when I declared my 10 rows earlier with the minimum I could get away with - a single column.
Obviously, this very issue indicates at more elegant ways in which a multidimensional array could be set up. The point, if there was one, is to point out the importance of initialising rows in our multidimensional arrays and point a finger at ways to do so.

Now, if I want to print the values of my grid, that is how I do it:
for i in 0…9 {
            for j in 0…9 {
                print(“\(i) \(j) \(grid[i][j])”)

I cannot claim to be ecstatic about the way I manipulated the array in order to get the result I wanted, but I did end up with a working multidimensional (or rather, two dimensional) array. I guess if it was all lovely and simple, there would not have been a need for this post…
One question I still don’t have an answer for is, how do I achieve everything I had achieved here in a case where I do not know the size of my matrix in advance. I can think of ways around it, but they all require some form of non elegant manoeuvring that is likely to get frowned upon by the purists. Purists whose feedback and inputs I’d love to have, BTW.