Wether you’re new to macOS or an user coming from different
machines, the tools we tend to use is very important to be
productive.
Here you’ll find my list and what I install on a fresh machine to
get started.
System tools
First and foremost, I start with
brew to handle all my
packages, but instead of doing so manually, I use my
dotfiles
and my “magic” install script that does all the heavy lifting for
me.
Keyboard tools
I use a TypeMatrix with a Colemak layout and also the internal
keyboard of my laptop with its default layout. Colemak layout is
available on a fresh macOS install but it is far from perfect as
there are a lot of missing dead keys (to type accented letters
mainly), so I start by installing the layout provided on this page:
Colemak mac
To easily switch between the two and get almost the same feeling, I
use
Karabiner Elements.
Everyday tools
sdkman: to manage installation of
various sdk (mainly Java based)
Now that iOS13 is available for more than year, we can start to set
it as a lower bound for our deployments.
This allows us to play with all sugar that Apple put in it, one of
the biggest thing is the arrival of SwiftUI to supercede UIKit
(write cross platform UIs and so on).
Bridging the two worlds
Using SwiftUI from UIKit
The first thing we might try to do, is embedding a SwiftUI View
inside our UIViewController based application. To do
so, Apple gives us UIHostingViewController which is a
simple bridging controller, straightforward to use.
structMyNewView:View{varview:someView{Text("I'm in SwiftUI")}}classMyNewViewViewController:UIHostingViewController{init(){super.init(rootView:MyNewView())}}
UIViewController in SwiftUI
However, at times we still need to reuse our good old
UIViewController, either because we can not afford a
full SwiftUI rewrite, so we want to keep old code and migrate pieces
by pieces or because we are using something not yet adapted to
SwiftUI.
In my case it was using the camera to scan a QRCode.
Non elegant solution
I faced a few issue with examples I found out, most of them are
adding an extension to the UIViewController that makes
it conform to UIViewControllerRepresentable.
classMyViewController:UIViewController{varcancellable:Cancellable?// classic stuff}extensionMyViewController:UIViewControllerRepresentable{publictypealiasUIViewControllerType=MyViewControllerpublicfuncmakeUIViewController(context_:UIViewControllerRepresentableContext<MyViewController>)->UIViewControllerType{self// don't .init() please, class instance is already available}publicfuncupdateUIViewController(_:UIViewControllerType,context_:UIViewControllerRepresentableContext<MyViewController>){}staticfuncdismantleUIViewController(_uiViewController:UIViewControllerType,coordinator_:Coordinator){uiViewController.cancellable?.cancel()}}structMyView:View{varbody:someView{MyViewController()}}
I find this not easy to read, as we’re doing weird thing by
returning self from a function named
makeUIViewController. Some example are telling to
return MyViewController() instead of self.
Please don’t do this otherwise you’re creating the
UIViewController twice for each call !
I also had a leak when using Combine (more to come
about this great framework), my Cancellables were never
freed, leading in a memory cycle that kept the
UIViewController living even though it was no longer
presented.
It is important to do proper house keeping in the
dismantleUIViewController method if you don’t want to
use too much memory and slow down your app.
Nice looking way of doing
You will find a working example below, basically we need to
implement a UIViewControllerRepresentable struct to
represent be the container for our UIViewController in
the SwiftUI world.
As I was working on an iOS project, I added unit tests to ensure
things are not behaving badly (and will not).
During the process, a common pattern showed up and a few fields were
required, I came up with the idea to basically create a
BaseTest for my tests, so that everything is unified.
Base idea
I came up with something like the following for my tests
It worked very well within XCode, I could run the tests by hitting
the 🔹 in the gutter.
Bad things happen
The thing that I discovered later (thanks to the CI feedback), is
that XCode was not properly discovering my tests as it should. At
first I blamed the fact that my new tests were not at the top level
of my sources folder (and the other ones were), but it was easy to
check that this was not the problem at all.
Then, I blamed fastlane and thought that I’ve missed
something in my test target configuration or something, but in fact,
the problem was similar when using classical
CMD + U key combo.
XCode was simply not discovering my test.
Workaround
Inheritance is often misused, in this case, I think it is relevant,
but I applied classical way of working around this. I changed my
BaseTest to a BaseHelper instead, to which
the test delegates the calls.
With this, the test class properly inherits
XCTestCase and is discovered as expected (even in
subfolders).
It’s been a very long time since last post (5 years…).
I am convinced that blogging is useful, at least for my present
self, and for my future self that tends to lose track of important
things.
What will this be about ?
In the past I blogged a lot about Java / Maven and so on,
my days have evolved to another languages, so I guess there will be
less JVM things (but may be a few Kotlin) and more Swift / Rust on
the other end.
Technical stack
In a blog reboot, we (I mean dev) like to follow the latest trend
and migrate our blog system to latest hype stack. I will avoid this
and focus on writing instead, so the site stays in its 15’ shape:
Il est courant maintenant d’utiliser Firebase dans les
applications mobiles. Que ce soit pour la partie statistiques, les
notifications ou le reporting des crashes.
L’intégration est très facile, mais peut devenir compliquée
dès lors qu’on manipule des target différentes avec
des configurations différentes. Cet article va vous détailler une
façon simple mais efficace de gérer ces différences.
Multiples fichiers plist
Les fichiers plist sont des fichiers XML de
configuration pour XCode. Lors de la création d’un
projet dans Firebase, il est possible de récupérer une version
générée contenant les bonnes variables pour votre projet. Le
problème qui peut se produire est lorsqu’on génère
plusieurs livrables avec des configurations qui doivent être
différentes grace aux target. Il n’est pas
possible, ni confortable, de gérer le cas de plusieurs
fichiers plist dans les sources. La redéfinition
du nom du fichier à faire utiliser par Firebase ne marche pas
à tous les coups et il a tendance à aller lire la valeur par
défaut GoogleService-Info.plist.
L’idée est donc d’utiliser un script au build qui
se chargera de configurer correctement le fichier
plist qui sera inclu dans le livrable.
Première étape : variabilisation
Pour être capable de générer le fichier
plist correctement, il est nécessaire de le
variabiliser. Dans mon cas, j’ai identifié les valeurs
suivantes qui devaient être variabilisées:
GOOGLE_APP_ID
BUNDLE_ID
CLIENT_ID
REVERSED_CLIENT_ID
J’ai donc ajouté des variables à la configuration de mon
build pour représenter ces valeurs qui doivent être
personnalisées. J’utilise des fichiers
.xcconfig mais ceci fonctionne également avec
l’ajout manuel (dans
Build Settings > + > Add User-Defined settings)
Unresolved directive in #excerpt -
include::site/static/lightbox.adoc[]
En plus de ça, j’ai modifié le fichier
GoogleService-Info.plist téléchargé sur Firebase
pour enlever les éléments qui allaient être remplacés à terme.
Plus exactement, j’ai remplacé les valeurs par des
chaînes du type WILL BE REPLACED AT BUILD TIME,
qui me permettent facilement de me rendre compte d’un
oubli de configuration.
Deuxième étape : génération du fichier
Une fois le fichier et l’environnement préparé, il ne
reste qu’à générer la version finale. Pour se faire, je
me base sur le système de build de XCode qui permet
de définir simplement des étapes. Les variables définies dans
la configuration du projet sont en effet disponibles
simplement lors de l’exécution des étapes de
build. En utilisant l’outil
defaults inclu dans macOS pour la manipulation
des fichiers plist, il est donc facile de définir
les valeurs attendues dans le fichier. J’ai ainsi
rajouté une étape shell script correspondant à ceci
dans le processus de build.
Enfin, il faut ordonner cette étape de build après
celle de copie des ressources, pour effectuer la modification
uniquement dans le fichier binaire de l’application et
non dans les sources du projet.
Bénéfices
Il est donc facile de disposer de configuration différente de
Firebase entre le debug et la release par
exemple. Ainsi vous pouvez tester l’envoi de
notification, par exemple, sans risquer de polluer des
utilisateurs de production, ou activer le
crash reporting uniquement en production par exemple.