Custom function in SQLite with fmdb

I’ve used Gus Mueller’s fmdb SQLite wrapper in most of my iOS projects and I’m in the process of migrating an app from Objective-C to Swift.

In this app, I needed a custom function for SQLite to compute the Haversine distance (giving great-circle distances between two points on a sphere from their longitudes and latitudes)

In all its glory*, here’s how I did it:

db.makeFunctionNamed("distance", arguments: 4) { context, argc, argv in
    guard db.valueType(argv[0]) == .float || db.valueType(argv[1]) == .float || db.valueType(argv[2]) == .float || db.valueType(argv[3]) == .float else {
        db.resultError("Expected double parameter", context: context)
        return
    }
    let lat1 = db.valueDouble(argv[0])
    let lon1 = db.valueDouble(argv[1])
    let lat2 = db.valueDouble(argv[2])
    let lon2 = db.valueDouble(argv[3])

    let lat1rad = DEG2RAD(lat1)
    let lat2rad = DEG2RAD(lat2)

    let distance = acos(sin(lat1rad) * sin(lat2rad) + cos(lat1rad) * cos(lat2rad) * cos(DEG2RAD(lon2) - DEG2RAD(lon1))) * 6378.1

    db.resultDouble(distance, context: context)
    
}

db is an FMDatabase, obviously.

This is how I use it:

let rs: FMResultSet? = db.executeQuery("SELECT ID, NO_BH, LAT, LONG, distance(?, ?, LAT, LONG) as distance FROM bh ORDER BY distance LIMIT 50", withArgumentsIn: [location.coordinate.latitude, location.coordinate.longitude])

Which gives me the 50 nearest points from location.

*Any improvement, remark greatly appreciated!

Hide Xcode 8 console garbage when running the simulator

Since Xcode 8, a lot of debug info appear in the console when using the iOS simulator:

2016-10-24 15:07:11.051609 sosasthma[19813:6302216] subsystem: com.apple.siri, category: Intents, enable_level: 1, persist_level: 1, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0

2016-10-24 15:07:11.070089 sosasthma[19813:6302540] subsystem: com.apple.UIKit, category: HIDEventFiltered, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0

2016-10-24 15:07:11.080159 sosasthma[19813:6302540] subsystem: com.apple.UIKit, category: HIDEventIncoming, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0

2016-10-24 15:07:11.089886 sosasthma[19813:6302537] subsystem: com.apple.BaseBoard, category: MachPort, enable_level: 1, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0

2016-10-24 15:07:11.101244 sosasthma[19813:6302216] subsystem: com.apple.UIKit, category: StatusBar, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0

2016-10-24 15:07:11.134 sosasthma[19813:6302216] [Crashlytics] Version 3.7.2 (112)

2016-10-24 15:07:11.174840 sosasthma[19813:6302537] subsystem: com.apple.libsqlite3, category: logging, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0

2016-10-24 15:07:11.185172 sosasthma[19813:6302549] subsystem: com.apple.network, category: , enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 2, enable_private_data: 0

To avoid having the console filled with info about siri, UIKIt, etc., just add

OS_ACTIVITY_MODE = disable

to your scheme in Product->Scheme->Edit Scheme
screen-shot-2016-10-24-at-15-06-45

Now you’ll have only your NSLog infos in your console. That’s enough garbage for a developer.

Source: Stack Overflow

Liste des appels Swisscom

(English version available here)

Ici en Suisse, mon opérateur téléphonique (Swisscom) a une option qui me permet de voir la liste des 20 derniers appels reçus ou manqués sur la page web de mon compte.

Ne désirant pas me connecter à cette page a chaque fois que je veux consulter cette liste afin de vérifier qui m’a appelé, j’ai écris quelques scripts qui récupèrent le contenu de cette page et l’affiche sur mon iPhone via une application iOS. Les noms sont récupérés depuis le carnet d’adresse et une notification est envoyée (via Prowl) quand un appel est reçu mais personne ne répond.

screen

Cette application iOS ne peut être distribuée en l’état sur l’AppStore car:

  • J’ai besoin des identifiants et mot de passe du compte Swisscom pour accéder à ces données et je n’aurai pas confiance dans un service qui me demanderait ces infos. Comme vous, je suppose.
  • La méthode utilisée pour récupérer la liste des appels n’est pas une méthode officielle et peut (comme cela est déjà arrivé) ne plus fonctionner si Swisscom change l’aspect de la page web.
  • L’application iOS peut rechercher le nom d’après un numéro inconnu via un appel à Local.ch (qui est plus ou moins l’annuaire suisse en ligne officiel). Bien sûr, il n’y a pas d’API officielle pour ce service et ils peuvent couper l’accès à tout moment. Soyez sympa et n’abusez pas de service.

J’ai mis le source à disposition sur GitHub: https://github.com/sburlot/phonecalls

Pour Swisscom

Si vous travaillez pour Swisscom, ou connaissez quelqu’un qui y travaille, demandez une méthode publique pour accéder à ces données, en proposant un login authentifié. Ca serait pratique et permettrait à cette app (et à d’autres!) d’être disponible pour le grand public.

Ou Swisscom pourrait ajouter cette fonctionnalité à leur application officielle,

Ou Swisscom pourrait m’embaucher pour implémenter cette fonctionnalité dans leur application. Je suis développeur freelance et disponible!

Quelques détails techniques

Sur le serveur, un script Perl va récupérer les données (via cron) du portail Swisscom et les enregistre dans une base MySQL (n’importe quelle base fonctionnerait).

L’application iOS appelle un script PHP sur le serveur: le serveur va récupérer les données de la base et renvoie un objet JSON.

Amusez-vous bien!

PS: bien sûr, je peux attendre d’être chez moi pour consulter les appels en absence sur mon téléphone, mais c’est moins geek et drôle. 😉

(Ceci est une version plus longue du post précédent en anglais)

Swisscom Phonecalls

(Version française disponible ici)

Here in Switzerland the major telco (Swisscom) has an option to let you see your last 20 answered and missed calls on your account webpage.

Not wanting to log in every time I want to check if I missed a call, I wrote some scripts and that fetches the content of my account web page and display them on an iOS app.

The names are fetched from the iPhone address book, and the iPhone receives a notification via Prowl when a call is missed.

screen

Or perhaps all this was an excuse to write some code during the holidays. Who knows.

I can’t make this app an official app because:

  • I need the Swisscom credentials to access the portal and I wouldn’t trust a stranger and give them access to my account. As you do.
  • The process of fetching the list of calls is not an officially approved method and may break (and did) when Swisscom changes the layout of the page.
  • The iOS app can also retrieve the owner of an unknown number via a call to the local.ch (more or less the official swiss white pages site). Of course, the API endpoint is not official nor public. Please be nice and don’t abuse this unofficial endpoint.

So I made the source available on GitHub: https://github.com/sburlot/phonecalls

For Swisscom

Oh, if you work for Swisscom, or know someone who does, ask for a method to fetch this data with a secure login option. That would be great, because I could make this app available via the AppStore.

Or Swisscom could add this feature to their official app. PLEASE.

Or Swisscom could hire me to implement this feature in their official app. I’m a freelance developer and I’m available!

Some tech details

On the server a Perl script fetches the data (via cron) from the Swisscom and stores the numbers in a MySQL database (any DB would work).
The iOS app calls a PHP script on the server to access the data: the PHP scripts fetches the data from the database and returns a JSON object.

Have fun!

PS: of course I can wait to return home and check my calls on my phone, but where’s the fun? 😉

I wrote this app 2 years ago and I still use it.

(this is a longer version of the original post)

Detect Touch outside a view

There are tasks that are not so simple (for me) to do on iOS. One of them is to detect a tap outside a view, for example to dismiss a modal dialog.

So, for reference, here’s how I implemented it.

First: you present a modal sheet using:

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion

In your interface, declare an UITapGestureRecognizer

@property (nonatomic, strong) UITapGestureRecognizer *gesture;

Then, in your implementation:

//==========================================================
- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    self.gesture = [[UITapGestureRecognizer alloc] 
      initWithTarget:self action:@selector(handleTap:)];
    self.gesture.numberOfTapsRequired = 1;
    self.gesture.numberOfTouchesRequired = 1;
    self.gesture.delegate = self;
    [self.gesture setCancelsTouchesInView:NO];
    [self.view.window addGestureRecognizer:self.gesture];
}

//==========================================================
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
      shouldReceiveTouch:(UITouch *)touch
{
    CGPoint point = [touch locationInView:nil];

    UIWindow *mainWindow = [[[UIApplication sharedApplication]
        delegate] window];
    CGPoint pointInSubview = [self.view convertPoint:point 
       fromView:mainWindow];
    if (!CGRectContainsPoint(self.view.frame, pointInSubview)) {
        [self close:self];
        return NO;
    }
    return YES; // handle the touch
}

//==========================================================
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer
{
    if (gestureRecognizer.state != UIGestureRecognizerStateEnded) {
        return;
    }
    // Handle the tap if you want to
}

//==========================================================
#pragma mark - Close modal
- (IBAction)close:(id)sender
{
    self.gesture.delegate = nil;
    [self.view.window removeGestureRecognizer:self.gesture];
    [self dismissViewControllerAnimated:YES completion:^{
    }];
}

That’s it. It could be easier.

Here’s a link to a Gist on GitHub, easier to read.

Catégories iOS

Convert & Split FLAC files

I had some .flac files that needed to be converted for iTunes, but I couldn’t find a standalone app for OSX, so using my CLI-fu, I managed to do the job.

For reference, this is how I proceeded (you’ll need Homebrew for this).

Install the following packages:

  • cuetools (to print the breakpoints from a cue or toc file)
  • shntool (to split a single-file album image to a file-per-track album)
  • flac (to read .flac file format)
  • ffmpeg (to do the conversion)
  • id3v2 (to read and write id3 tags)
  • mmv (to change the name of files, see below)

mmv is not really needed, but this tool is invaluable, you should use it.

brew install cuetools shntool flac ffmpeg mmv id3v2

First, split the flac file in tracks:

cuebreakpoints album.cue | shnsplit -o flac album.flac

Add the tags to the tracks

cuetag.sh album.cue split-track*.flac

Rename the files (why? because!)

mmv 'split-track??.flac' "Track#1#2.flac"

Concert the .flac files to mp3 VBR

(for FILE in Track*.flac ; do ffmpeg -i "$FILE" -codec:a libmp3lame -qscale:a 1 "`basename "$FILE" .flac`.mp3" || break; done)

You can now import the *.mp3 files in iTunes.

I couldn’t find a way to convert the .flac files to .m4e AND keep the metadata so I used mp3. If anyone knows a way, let me know. I also read that the ffmpeg aac converter wasn’t as good as iTunes, so I don’t think it’s really worth it.

Catégories OSX

UIAutomation, nice to meet you

I wrote an app for a museum and it needs to run for a very long time without crashing. Unfortunately, it crashed after a week. (I had 3 days to write the app, and almost no time to test it. Yes, we developers always have an excuse!)

So I had a look to UIAutomation. What a revelation! I wrote a script to test my app and I was able to remove some leaks from my app, but I needed something more hard-core to test my app.

I searched the internets using DuckDuckGo, my favorite searching tool for the last year. I searched for « UIAutomation Monkey » because, being an old Macintosh developer, I remembered of the infamous « Monkey Lives » feature of the early Macs.

I quickly found « UI AutoMonkey » by Jonathan Penn.

Seeing this script clicking frantically is really fun, and helped me find some unexpected bugs.

I was able to let it run for around 6 hours, without crashing and memory usage stays constant. So far so good.

I will install the new app next week, we’ll see how it behaves.

Notes:

  • I couldn’t run the test for more than 6 hours, Instruments used 10G of memory and wasn’t showing me the memory usage of my app;
  • ARC is cool, but I feel I lost control of my app;
  • Writing an app that needs to run 24/24 without ever restarting is stressful.

Start VPN when waking up

On my Linode server (great company and service BTW), I had setup a VPN for me, but after upgrading to Ubuntu 14.04, I had no time to reinstall it.

So yesterday, I grabbed a free account on NoLimitVPN (because NSA and Google, you know) and I’ve been using it without any problems. (I’m no expert in security, but since NoLimitVPN is managed by a french company and their VPN is hosted on RamNode.com in the Netherlands, I expect a minimum of privacy).

The only problem I had was that the VPN doesn’t connect automatically when my Mac wakes up. DuckDuckGoing (what’s the official or usual verb ?) (because I don’t use Google anymore), I only found AppleScripts running in background and connecting the VPN. Since I don’t want something running in the background on my old and faithful iMac, I looked for alternatives.

This is the solution I’ve set up on my Mac:

To start the VPN (named « VPN », duh), I use a terminal command

scutil --nc start VPN

Instead of this AppleScript (found on StackOverflow)

    
tell application "System Events"
    tell current location of network preferences
        set myConnection to the service "VPN"
        if myConnection is not null then
            if current configuration of myConnection is not connected then
                connect myConnection
            end if
        end if
    end tell
    return 120
end tell

To start the VPN when waking up, I use SleepWatcher (a tool I use to pause ArqBackup when my Mac wakes up) and I put this line in my ~/.wakeup file:

scutil --nc start VPN > /dev/null 2>&1

Voila, problem solved.

Catégories OSX

Check your missed calls from your iPhone

Here in Switzerland the major telco (Swisscom) has an option to let you see your last 20 answered and missed calls on your account webpage.

Not wanting to log in every time I want to check if I missed a call, I wrote some scripts and that fetches the content of my account web page and display them on an iOS app.

Lire la suite…