<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://www.jeyries.fr/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.jeyries.fr/blog/" rel="alternate" type="text/html" /><updated>2024-02-16T09:14:11+00:00</updated><id>https://www.jeyries.fr/blog/feed.xml</id><title type="html">Julien Eyriès blog</title><subtitle>Julien Eyriès blog</subtitle><entry><title type="html">Classic 4</title><link href="https://www.jeyries.fr/blog/2021/02/01/classic-4" rel="alternate" type="text/html" title="Classic 4" /><published>2021-02-01T00:00:00+00:00</published><updated>2021-02-01T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2021/02/01/classic-4</id><content type="html" xml:base="https://www.jeyries.fr/blog/2021/02/01/classic-4"><![CDATA[<p>Classic 4 - free iPhone, iPad and Apple TV app. No advertising, no in-app purchases, no tracking.</p>

<p>The goal of the game is very simple: line up 4 checkers vertically, horizontally, or diagonally to win. It’s a fun and strategic game, which you can play for free and without advertising!</p>

<p>This game is also known as “Connect 4”, or “Four in a row” .</p>

<p>The game engine is written in C++ and based on the <a href="https://en.wikipedia.org/wiki/Monte_Carlo_tree_search">Monte Carlo Tree Search</a> algorithm.</p>

<p>More information here:</p>

<p><a href="https://www.jeyries.fr/classic4">Classic 4</a></p>]]></content><author><name></name></author><summary type="html"><![CDATA[Classic 4 - free iPhone, iPad and Apple TV app. No advertising, no in-app purchases, no tracking.]]></summary></entry><entry><title type="html">Grandma Calculator</title><link href="https://www.jeyries.fr/blog/2021/01/01/grandma-calculator" rel="alternate" type="text/html" title="Grandma Calculator" /><published>2021-01-01T00:00:00+00:00</published><updated>2021-01-01T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2021/01/01/grandma-calculator</id><content type="html" xml:base="https://www.jeyries.fr/blog/2021/01/01/grandma-calculator"><![CDATA[<p>Grandma Calculator - free iPad app, no advertising, no in-app purchases, no tracking.</p>

<p>I recently bought an iPad for my mom - 69 years old. She used to use an Android tablet, so I put an Apple product in her hand… The transition went smoothly, she’s very happy with her iPad.</p>

<p>There is only one missing thing: the calculator. It is very important for her to be able to do her accounting. Well, it’s a strange thing for Apple, even in 2021, the iPad doesn’t have a calculator provided by default … It is present on the iPhone, Mac but not on iPad 🙃</p>

<p>So, let’s go to the App Store. And here, second surprise, the App Store is full of calculators for iPad! But there is a trick: these apps are full of ads, in-app purchases…</p>

<p>So I wrote for my mom a calculator without advertising, without in-app purchases, without tracking.</p>

<p>No need for complex functions either, my mom just needs the basic operators: addition, subtraction, multiplication, division, percentages .</p>

<p>More information here:</p>

<p><a href="https://www.jeyries.fr/calculator">Grandma Calculator</a></p>]]></content><author><name></name></author><summary type="html"><![CDATA[Grandma Calculator - free iPad app, no advertising, no in-app purchases, no tracking.]]></summary></entry><entry><title type="html">Comment charger une image de manière asynchrone ? Une vue d’ensemble de quelques méthodes disponibles</title><link href="https://www.jeyries.fr/blog/2020/10/13/chargement-image-asynchrone-part-6-overview" rel="alternate" type="text/html" title="Comment charger une image de manière asynchrone ? Une vue d’ensemble de quelques méthodes disponibles" /><published>2020-10-13T00:00:00+00:00</published><updated>2020-10-13T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2020/10/13/chargement-image-asynchrone-part-6-overview</id><content type="html" xml:base="https://www.jeyries.fr/blog/2020/10/13/chargement-image-asynchrone-part-6-overview"><![CDATA[<p>Résumé: Comment charger une image de manière asynchrone ? C’est une question que tout développeur iOS s’est un jour posé.</p>

<h1 id="description">Description</h1>

<p>En effet Apple n’a jamais jugé necessaire de publier une API officielle sur le sujet.</p>

<p>Ce n’est pas vraiment un problème tant de nombreux framework sont venus apporter leur solution au chargement d’image asynchrone.</p>

<p>Par exemple, j’utilise personnellement à cet effet le framework <a href="https://github.com/onevcat/Kingfisher">KingFisher</a>.</p>

<p>Cependant, certains éditeurs prefèrent éviter des dépendances vers des frameworks externes. Ce peut être une bonne raison pour mettre au point sa propre version du chargement d’image asynchrone.</p>

<p>Par ailleurs, cela fait une bonne question pour un entretien en vue d’embaucher un développeur iOS . J’ai moi-même vu cette question sortir plus d’une fois depuis 10 ans que je fais du développement iOS :-)</p>

<p>A ce sujet, je tiens à féliciter les compagnies comme <a href="https://zen.ly">Zenly</a> qui jouent fair-play en indemnisant les candidats pour passer du temps à coder les problèmes demandés en entretien. Chapeau !</p>

<h1 id="vue-densemble">Vue d’ensemble</h1>

<p>Voici donc quelques méthodes disponibles pour charger une image de manière asynchrone:</p>

<ul>
  <li><a href="/2016/04/01/asynchronous-image-loading-part-1a-objective-c">UIKit in Objective-C using ReactiveCocoa</a></li>
  <li><a href="/2016/04/02/asynchronous-image-loading-part-1b-objective-c">… adding associated objects.</a></li>
  <li><a href="/2019/05/10/chargement-image-asynchrone-part-2-swift-uitableviewcell">avec Swift dans une UITableViewCell custom</a></li>
  <li><a href="/2019/01/25/chargement-image-asynchrone-part-3-swift-fichier-operation-queue-uicollectionviewcell">Depuis un fichier avec Swift et une OperationQueue, vers une UICollectionViewCell</a></li>
  <li><a href="/2017/01/06/chargement-image-asynchrone-part-4a-uikit-swift-closures">UIKit + Swift + closures</a></li>
  <li><a href="/2017/01/07/chargement-image-asynchrone-part-4b-uikit-swift-closures">… avec des associated objects</a></li>
  <li><a href="/2020/10/12/chargement-image-asynchrone-part-5-rxswift">avec RxSwift</a></li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: Comment charger une image de manière asynchrone ? C’est une question que tout développeur iOS s’est un jour posé.]]></summary></entry><entry><title type="html">Comment charger une image de manière asynchrone ? avec RxSwift</title><link href="https://www.jeyries.fr/blog/2020/10/12/chargement-image-asynchrone-part-5-rxswift" rel="alternate" type="text/html" title="Comment charger une image de manière asynchrone ? avec RxSwift" /><published>2020-10-12T00:00:00+00:00</published><updated>2020-10-12T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2020/10/12/chargement-image-asynchrone-part-5-rxswift</id><content type="html" xml:base="https://www.jeyries.fr/blog/2020/10/12/chargement-image-asynchrone-part-5-rxswift"><![CDATA[<p>Résumé: Cette version permet de charger une image de manière asynchrone depuis une URL avec RxSwift</p>

<h1 id="description">Description</h1>

<p>On utilise pour cela les helpers définis dans mon post précédent: <a href="/2020/09/23/rxswift-helper-for-network-image-and-json-decoding">A RxSwift helper for network calls, JSON decoding and image decoding</a></p>

<p>L’operation de chargement des données depuis le réseau et celle de décodage en tâche de fond sont combinées à l’aide de l’opérateur <code class="language-plaintext highlighter-rouge">flatMap</code>.</p>

<p>L’implementation repose sur <code class="language-plaintext highlighter-rouge">URLSession</code> pour le téléchargement et sur <code class="language-plaintext highlighter-rouge">NSCache</code> pour cacher les images. De plus, un niveau de cache supplémentaire <code class="language-plaintext highlighter-rouge">URLCache</code> sert à cacher les réponses du réseau.</p>

<h1 id="asyncimageloaderswift">AsyncImageLoader.swift</h1>

<p>L’interface publique est plutôt simple:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">fetchObservable</code>: Cette methode retourne un observable de type <code class="language-plaintext highlighter-rouge">Single&lt;UIImage&gt;</code> à partir de l’url fournie</li>
</ul>

<script src="https://gist.github.com/c7bf9e0cc5531538a262fc0694b4158c.js"> </script>

<h1 id="camerarollcellswift">CameraRollCell.swift</h1>

<p>Un exemple d’utilisation ce chargement d’image dans une <code class="language-plaintext highlighter-rouge">UICollectionViewCell</code>.</p>

<p>Note: ici, l’utilisation du <code class="language-plaintext highlighter-rouge">DisposeBag</code> permet d’annuler un chargement déjà en cours lors d’un défilement par exemple.</p>

<script src="https://gist.github.com/67231f4a8140a877475527f76f24ebb7.js"> </script>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: Cette version permet de charger une image de manière asynchrone depuis une URL avec RxSwift]]></summary></entry><entry><title type="html">[Bitcoin] Comment récupérer des fonds à partir d’un fichier wallet.dat de Bitcoin Core sans avoir à télécharger toute la blockchain ?</title><link href="https://www.jeyries.fr/blog/2020/09/25/bitcoin-recuperer-des-fonds" rel="alternate" type="text/html" title="[Bitcoin] Comment récupérer des fonds à partir d’un fichier wallet.dat de Bitcoin Core sans avoir à télécharger toute la blockchain ?" /><published>2020-09-25T00:00:00+00:00</published><updated>2020-09-25T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2020/09/25/bitcoin-recuperer-des-fonds</id><content type="html" xml:base="https://www.jeyries.fr/blog/2020/09/25/bitcoin-recuperer-des-fonds"><![CDATA[<p>Résumé: Vous avez envoyé des fonds à une adresse de réception de Bitcoin Core. Malheureusement il vous reste encore plus d’une semaine pour synchroniser la blockchain. Et vous ne voulez pas attendre une synchronisation complète de la blockchain avant de transférer vos fonds ..</p>

<h1 id="le-problème">Le problème</h1>

<p>Vous avez envoyé des fonds à une adresse de réception de Bitcoin Core. Malheureusement il vous reste encore plus d’une semaine pour synchroniser la blockchain. Et vous ne voulez pas attendre une synchronisation complète de la blockchain avant de transférer vos fonds ..</p>

<h1 id="la-procédure-en-bref">La procédure en bref</h1>

<ul>
  <li>Installer un nouveau porte-monnaie électronique</li>
  <li>Utiliser la ligne de commande <code class="language-plaintext highlighter-rouge">bitcoin-cli</code> pour communiquer avec le démon <code class="language-plaintext highlighter-rouge">bitcoind</code></li>
  <li>Rassembler des informations</li>
  <li>Créer une transaction</li>
  <li>Signer la transaction</li>
  <li>Broadcaster la transaction</li>
</ul>

<h1 id="étapes-">Étapes :</h1>

<h2 id="installez-un-nouveau-portefeuille">Installez un nouveau portefeuille</h2>

<ul>
  <li>installer un nouveau portefeuille, par exemple Electrum</li>
  <li>récupérer une adresse de réception de votre nouveau portefeuille</li>
</ul>

<p>Dans mon cas: <code class="language-plaintext highlighter-rouge">bc1q86dhxl3xfuy4ag2zcz7wercud9lp63t5crhp8m</code></p>

<h2 id="recupérez-les-infos-de-la-précédente-transaction">Recupérez les infos de la précédente transaction</h2>

<p>Récupérez l’adresse sur laquelle se trouvent les fonds dans l’ancien portefeuille</p>

<p>Dans mon cas: <code class="language-plaintext highlighter-rouge">bc1q0f0elkl5q7njxp67maja63jpmgds6s67u3zg0w</code></p>

<ul>
  <li>récupérer la transaction qui a amené les fonds - par exemple en faisant une recherche sur le site <a href="https://www.blockchain.com/">blockchain.com</a></li>
</ul>

<p>Dans mon cas, voici l’adresse de départ: <a href="https://www.blockchain.com/fr/btc/address/bc1q0f0elkl5q7njxp67maja63jpmgds6s67u3zg0w">https://www.blockchain.com/fr/btc/address/bc1q0f0elkl5q7njxp67maja63jpmgds6s67u3zg0w</a></p>

<p>et la transaction:
<a href="https://www.blockchain.com/btc/tx/03a9b2ff64f52b298927ed0d7ad6aa21fc4952a0954177f3eb5a6fa953df78d6">https://www.blockchain.com/btc/tx/03a9b2ff64f52b298927ed0d7ad6aa21fc4952a0954177f3eb5a6fa953df78d6</a></p>

<ul>
  <li>notez le montant de bitcoin que vous voulez transférer</li>
  <li>examinez la transaction</li>
  <li>récuperez “txid”, c’est le transaction id - “Hachage” sur blockchain.com</li>
  <li>récuperez “vout”, c’est l’indice de la sortie qui concerne votre adresse - “Indice” sur blockchain.com</li>
  <li>récuperez le “scriptPubKey”, c’est le “Pkscript” sur blockchain.com, en mode hexa.</li>
</ul>

<h2 id="estimez-les-frais-de-transaction">Estimez les frais de transaction</h2>

<p>Choisissez le “fee”, qui correspondent aux frais de transaction. Veuillez consulter ce site pour connaître un tarif correct : <a href="https://bitcoinfees.earn.com/">https://bitcoinfees.earn.com/</a>. Un exemple de ce que vous indique ce site:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Which fee should I use?

For the median transaction size of 224 bytes, this results in a fee of 0.00013888 BTC.

</code></pre></div></div>
<h2 id="créez-la-nouvelle-transaction-">Créez la nouvelle transaction .</h2>

<p>Ici, on utilise <code class="language-plaintext highlighter-rouge">bitcoin-cli</code> pour communiquer avec <code class="language-plaintext highlighter-rouge">bitcoind</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>createrawtransaction [{"txid":"hex","vout":n,"sequence":n},...] [{"address":amount},{"data":"hex"},...] ( locktime replaceable )
</code></pre></div></div>

<p>remplissez les paramètres suivants:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>txid: votre transaction id
vout: vout
adresse: l'adresse de réception
amount: le montant final = le montant initial - les frais de transaction
</code></pre></div></div>

<p>par exemple dans mon cas:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>createrawtransaction "[{\"txid\":\"03a9b2ff64f52b298927ed0d7ad6aa21fc4952a0954177f3eb5a6fa953df78d6\",\"vout\":31}]" "{\"bc1q86dhxl3xfuy4ag2zcz7wercud9lp63t5crhp8m\":0.00210026}"
</code></pre></div></div>

<p>vous obtenez la transaction en hexa:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0200000001d678df53a96f5aebf3774195a05249fc21aad67a0ded2789292bf564ffb2a9031f00000000ffffffff016a340300000000001600143e9b737e264f095ea142c0bcec8f1c697e1d457400000000
</code></pre></div></div>

<p>Si vous obtenez une erreur, vous avez probablement supprimé accidentellement un guillemet ou une barre oblique inversée. Vérifiez soigneusement votre chaîne et réessayez.</p>

<p>Ensuite, nous allons signer la transaction en vue de sa diffusion. Pour cela il vous faut la clé privée correspondant à l’adresse de départ.</p>

<h2 id="recupérez-la-clé-privée">Recupérez la clé privée</h2>

<p>Toujours avec <code class="language-plaintext highlighter-rouge">bitcoin-cli</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dumpprivkey "address"
</code></pre></div></div>

<p>address: adresse de départ</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dumpprivkey bc1q0f0elkl5q7njxp67maja63jpmgds6s67u3zg0w
</code></pre></div></div>

<p>On obtient:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>L4752xBnTYrmhqa24ZWB8oKEENJD9FosEN1Z1jDtcF7gemvgj6fR
</code></pre></div></div>

<h2 id="signez-la-transaction">Signez la transaction</h2>

<p>Dans <code class="language-plaintext highlighter-rouge">bitcoin-cli</code>:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>signrawtransactionwithkey "hexstring" ["privatekey",...] ( [{"txid":"hex","vout":n,"scriptPubKey":"hex","redeemScript":"hex","witnessScript":"hex","amount":amount},...] "sighashtype" )
</code></pre></div></div>

<p>amount: le montant total = montant final + les frais</p>

<p>par exemple dans mon cas:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>signrawtransactionwithkey "0200000001d678df53a96f5aebf3774195a05249fc21aad67a0ded2789292bf564ffb2a9031f00000000ffffffff016a340300000000001600143e9b737e264f095ea142c0bcec8f1c697e1d457400000000" "[\"L4752xBnTYrmhqa24ZWB8oKEENJD9FosEN1Z1jDtcF7gemvgj6fR\"]" "[{\"txid\":\"03a9b2ff64f52b298927ed0d7ad6aa21fc4952a0954177f3eb5a6fa953df78d6\",\"vout\":31,\"amount\":0.00224362,\"scriptPubKey\":\"00147a5f9fdbf407a723075edf65dd4641da1b0d435e\"}]"
</code></pre></div></div>

<p>S’il n’y a pas d’erreurs, vous devriez avoir une transaction signée ! C’était la partie difficile. Vous avez simplement créé à la main une transaction bitcoin et utilisé votre clé privée pour la signer. Le résultat ressemble à cela:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
  "hex": "02000000000101d678df53a96f5aebf3774195a05249fc21aad67a0ded2789292bf564ffb2a9031f00000000ffffffff016a340300000000001600143e9b737e264f095ea142c0bcec8f1c697e1d45740247304402207d425a5273fcf65f8b43ffbd7554fa057785d7ef2449278a05a95aa37a8db0db022011ea799d6e13f07feb9fc4a02929b0fc9a101d974502be2c6d3abf33419d55f50121031a2e7e647c2cc33f03ecfc4092e93ec6220edce69e961fc7bc525522a4d0d8e300000000",
  "complete": true
}
</code></pre></div></div>

<h2 id="diffusez-la-transaction">Diffusez la transaction</h2>

<p>Cette valeur hexadécimale peut être envoyée directement au réseau Bitcoin pour être incluse dans la blockchain.</p>

<p>Enfin, allez à : <a href="https://www.blockchain.com/btc/pushtx">https://www.blockchain.com/btc/pushtx</a>
Collez la chaîne hexadécimale et cliquez sur “Envoyer la transaction”</p>

<p>Vous devriez alors voir une nouvelle transaction entrante dans votre nouveau portefeuille.</p>

<h2 id="-profitez--">💵🥳💵 Profitez ! 💵🥳💵</h2>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: Vous avez envoyé des fonds à une adresse de réception de Bitcoin Core. Malheureusement il vous reste encore plus d’une semaine pour synchroniser la blockchain. Et vous ne voulez pas attendre une synchronisation complète de la blockchain avant de transférer vos fonds ..]]></summary></entry><entry><title type="html">[Bitcoin] Installer le logiciel Bitcoin sur macOS</title><link href="https://www.jeyries.fr/blog/2020/09/24/bitcoin-installation-macos" rel="alternate" type="text/html" title="[Bitcoin] Installer le logiciel Bitcoin sur macOS" /><published>2020-09-24T00:00:00+00:00</published><updated>2020-09-24T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2020/09/24/bitcoin-installation-macos</id><content type="html" xml:base="https://www.jeyries.fr/blog/2020/09/24/bitcoin-installation-macos"><![CDATA[<p>Résumé: Comment installer le logiciel Bitcoin sur macOS, et synchroniser la blockchain .</p>

<h1 id="coinbase">Coinbase</h1>

<p>Donc vous avez, comme moi, décidé de découvrir le monde merveilleux du Bitcoin. Pour commencer, par exemple, vous ouvrez un compte chez <a href="https://www.coinbase.com">Coinbase</a> et convertissez quelques euros en BTC.</p>

<h1 id="bitcoin-core">Bitcoin Core</h1>

<p>Ensuite, pour on installe le logiciel fondateur du système, <a href="https://bitcoin.org/fr/telecharger">Bitcoin Core</a>, codé à la base par l’enigmatique <a href="https://fr.wikipedia.org/wiki/Satoshi_Nakamoto">M. Satoshi</a> …</p>

<p>Je l’installe <code class="language-plaintext highlighter-rouge">brew cask install bitcoin-core</code>. Le logiciel se lance, je choisi de stocker la blockchain sur un disque externe (et oui, il y en a pour plus de 300 Go..) et j’attend… il y en a pour plus d’une semaine. Et cerise sur le gateau l’UI de Bitcoin Core freeze dès qu’on navigue un peu dans l’application.</p>

<h1 id="bitcoind">bitcoind</h1>

<p>C’est le genre de problème qui me fait installer directement la version en ligne de commande: <code class="language-plaintext highlighter-rouge">brew install bitcoin</code> . Je lance le démon <code class="language-plaintext highlighter-rouge">bitcoind</code>.</p>

<p>Afin d’ameliorer la vitesse de synchronisation, j’effectue quelques réglage dans le fichier de configuration <code class="language-plaintext highlighter-rouge">bitcoin.conf</code> :</p>
<ul>
  <li>plus de mémoire cache</li>
  <li>ajouts de nodes trouvés sur https://bitnodes.io</li>
</ul>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>listen=0
dbcache=4096
banscore=10

# France
addnode=51.83.67.9:8333
addnode=51.210.34.62:8333
addnode=51.68.208.252:8333
addnode=5.196.73.52:8333

# Germany
addnode=116.203.187.251:8333
addnode=134.209.228.52:8333
addnode=207.154.210.209:8333
addnode=46.101.198.6:8333

# US
addnode=18.222.118.166:8333
addnode=159.89.42.205:8333
addnode=136.52.114.123:8333
addnode=72.178.123.6:8333
</code></pre></div></div>

<p>Et c’est reparti, la blockchain se télécharge à bonne vitesse, mais il reste encore quelques jours à attendre. Bien sûr, j’aurai pu attendre quelques jours de plus. D’un autre coté, j’ai envie de jouer avec mes Bitcoins ;-) .</p>

<h1 id="electrum">Electrum</h1>

<p>Une autre application me tente: <a href="https://electrum.org">Electrum</a>. Son avantage, c’est qu’Electrum est rapide, car il utilise des serveurs qui indexent la blockchain.</p>

<p>Je l’installe: <code class="language-plaintext highlighter-rouge">brew cask install electrum</code> et je crée un nouveau wallet. Maintenant il ne reste plus qu’a effectuer une transaction pour transferer mes fonds depuis Bitcoin Core vers Electrum…</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: Comment installer le logiciel Bitcoin sur macOS, et synchroniser la blockchain .]]></summary></entry><entry><title type="html">A RxSwift helper for network calls, JSON decoding and image decoding</title><link href="https://www.jeyries.fr/blog/2020/09/23/rxswift-helper-for-network-image-and-json-decoding" rel="alternate" type="text/html" title="A RxSwift helper for network calls, JSON decoding and image decoding" /><published>2020-09-23T00:00:00+00:00</published><updated>2020-09-23T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2020/09/23/rxswift-helper-for-network-image-and-json-decoding</id><content type="html" xml:base="https://www.jeyries.fr/blog/2020/09/23/rxswift-helper-for-network-image-and-json-decoding"><![CDATA[<p>Summary: We propose a small helper in order to perform some classical asynchronous operations in <code class="language-plaintext highlighter-rouge">RxSwift</code> like: loading some <code class="language-plaintext highlighter-rouge">Data</code> with <code class="language-plaintext highlighter-rouge">URLSession</code>, decoding these <code class="language-plaintext highlighter-rouge">Data</code> onto some <code class="language-plaintext highlighter-rouge">Decodable</code> element or decoding these <code class="language-plaintext highlighter-rouge">Data</code> onto an <code class="language-plaintext highlighter-rouge">UIImage</code> .</p>

<h1 id="rxswift">RxSwift</h1>

<p>RxSwift is ReactiveX for Swift.</p>

<p>More info here: <a href="https://github.com/ReactiveX/RxSwift">https://github.com/ReactiveX/RxSwift</a></p>

<h1 id="description">Description</h1>

<p>We propose a small helper in order to perform some classical operations in <code class="language-plaintext highlighter-rouge">RxSwift</code> like: loading some <code class="language-plaintext highlighter-rouge">Data</code> with <code class="language-plaintext highlighter-rouge">URLSession</code>, decoding these <code class="language-plaintext highlighter-rouge">Data</code> onto some <code class="language-plaintext highlighter-rouge">Decodable</code> element or decoding these <code class="language-plaintext highlighter-rouge">Data</code> onto an <code class="language-plaintext highlighter-rouge">UIImage</code> .</p>

<p>These operations can benefit from being performed asynchronously with the help of RxSwift.</p>

<p>The helper is made of 3 building blocks:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">URLSession.download</code>: takes an <code class="language-plaintext highlighter-rouge">URL</code> and produce a <code class="language-plaintext highlighter-rouge">Single&lt;Data&gt;</code></li>
  <li><code class="language-plaintext highlighter-rouge">DecodeHelper.decode</code>: takes some <code class="language-plaintext highlighter-rouge">Data</code> and produce a <code class="language-plaintext highlighter-rouge">Single&lt;T&gt;</code> where <code class="language-plaintext highlighter-rouge">T</code> conforms to <code class="language-plaintext highlighter-rouge">Decodable</code></li>
  <li><code class="language-plaintext highlighter-rouge">ImageHelper.decode</code>: takes some <code class="language-plaintext highlighter-rouge">Data</code> and produce a <code class="language-plaintext highlighter-rouge">Single&lt;UIImage&gt;</code></li>
</ul>

<p>These building blocks can be combined with <code class="language-plaintext highlighter-rouge">flatMap</code>, like below :</p>

<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="kd">class</span> <span class="kt">RandomUserService</span><span class="p">:</span> <span class="kt">RandomUserServiceProtocol</span> <span class="p">{</span>
    
    <span class="kd">func</span> <span class="nf">contentObservable</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="kt">Single</span><span class="o">&lt;</span><span class="kt">RandomUserAPI</span><span class="o">.</span><span class="kt">Content</span><span class="o">&gt;</span> <span class="p">{</span>
        
        <span class="k">return</span> <span class="kt">URLSession</span><span class="o">.</span><span class="n">shared</span><span class="o">.</span><span class="nf">download</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="kt">RandomUserAPI</span><span class="o">.</span><span class="n">url</span><span class="p">)</span>
            <span class="o">.</span><span class="nf">flatMap</span><span class="p">(</span> <span class="kt">DecodeHelper</span><span class="o">.</span><span class="n">decode</span> <span class="p">)</span>
    <span class="p">}</span>
    
    
<span class="p">}</span>

</code></pre></div></div>

<h1 id="urlsessionrxswiftswift">URLSession+RxSwift.swift</h1>

<p>This extension will help for doing network calls with RxSwift.</p>

<script src="https://gist.github.com/7be2d1f465711b7fa736a113a4452631.js"> </script>

<h1 id="decodehelperswift">DecodeHelper.swift</h1>

<p>This module will help for doing JSON decode in RxSwift.</p>

<script src="https://gist.github.com/25674dd81ab5315b460bf76f5dec24d2.js"> </script>

<h1 id="imagehelperswift">ImageHelper.swift</h1>

<p>This will help for doing image decode with RxSwift.</p>

<script src="https://gist.github.com/d3db83e9aca95163655f8f804ba0721c.js"> </script>]]></content><author><name></name></author><summary type="html"><![CDATA[Summary: We propose a small helper in order to perform some classical asynchronous operations in RxSwift like: loading some Data with URLSession, decoding these Data onto some Decodable element or decoding these Data onto an UIImage .]]></summary></entry><entry><title type="html">Comment charger une image de manière asynchrone ? avec Swift dans une UITableViewCell custom</title><link href="https://www.jeyries.fr/blog/2019/05/10/chargement-image-asynchrone-part-2-swift-uitableviewcell" rel="alternate" type="text/html" title="Comment charger une image de manière asynchrone ? avec Swift dans une UITableViewCell custom" /><published>2019-05-10T00:00:00+00:00</published><updated>2019-05-10T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2019/05/10/chargement-image-asynchrone-part-2-swift-uitableviewcell</id><content type="html" xml:base="https://www.jeyries.fr/blog/2019/05/10/chargement-image-asynchrone-part-2-swift-uitableviewcell"><![CDATA[<p>Résumé: C’est la version la plus minimaliste pour charger une image de manière asynchrone avec Swift dans une UITableViewCell custom.</p>

<h1 id="description">Description</h1>

<p>On utilise <code class="language-plaintext highlighter-rouge">URLSession</code> pour charger les données de l’image. Le décodage se fait directement dans la queue en background de <code class="language-plaintext highlighter-rouge">URLSession</code>. On retourne le resultat dans la queue principale <code class="language-plaintext highlighter-rouge">DispatchQueue.main</code> et on l’affecte à <code class="language-plaintext highlighter-rouge">UIImageView</code>. Enfin 
on retient le <code class="language-plaintext highlighter-rouge">URLSessionDataTask</code> dans la <code class="language-plaintext highlighter-rouge">UITableViewCell</code>, pour pouvoir annuler le chargement en cas de défilement.</p>

<h1 id="bookcellswift">BookCell.swift</h1>

<script src="https://gist.github.com/c4c446e6c9798f188af9226b0a96ef1f.js"> </script>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: C’est la version la plus minimaliste pour charger une image de manière asynchrone avec Swift dans une UITableViewCell custom.]]></summary></entry><entry><title type="html">Comment charger une image de manière asynchrone ? Depuis un fichier avec Swift et une OperationQueue, vers une UICollectionViewCell</title><link href="https://www.jeyries.fr/blog/2019/01/25/chargement-image-asynchrone-part-3-swift-fichier-operation-queue-uicollectionviewcell" rel="alternate" type="text/html" title="Comment charger une image de manière asynchrone ? Depuis un fichier avec Swift et une OperationQueue, vers une UICollectionViewCell" /><published>2019-01-25T00:00:00+00:00</published><updated>2019-01-25T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2019/01/25/chargement-image-asynchrone-part-3-swift-fichier-operation-queue-uicollectionviewcell</id><content type="html" xml:base="https://www.jeyries.fr/blog/2019/01/25/chargement-image-asynchrone-part-3-swift-fichier-operation-queue-uicollectionviewcell"><![CDATA[<p>Résumé: Cette version permet de charger une image de manière asynchrone depuis un fichier avec Swift et une OperationQueue, vers une UICollectionViewCell.</p>

<h1 id="description">Description</h1>

<p>On utilise <code class="language-plaintext highlighter-rouge">OperationQueue</code> pour charger depuis un fichier et decoder les données de l’image, tout cela en arrière plan. Si besoin on peut limiter le nombre des operations concurrentes avec <code class="language-plaintext highlighter-rouge">maxConcurrentOperationCount</code>.</p>

<p>De plus, un <code class="language-plaintext highlighter-rouge">NSCache</code> est utilisé pour cacher les images décodées.</p>

<p>Enfin on retient l’objet <code class="language-plaintext highlighter-rouge">Operation</code> dans la <code class="language-plaintext highlighter-rouge">UICollectionViewCell</code>, pour pouvoir annuler le chargement en cas de défilement.</p>

<h1 id="operationqueue">OperationQueue</h1>

<p>Plus d’info sur <code class="language-plaintext highlighter-rouge">OperationQueue</code> ici: <a href="https://developer.apple.com/documentation/foundation/operationqueue">https://developer.apple.com/documentation/foundation/operationqueue</a></p>

<h1 id="imageloaderswift">ImageLoader.swift</h1>

<script src="https://gist.github.com/338264195b6d48a14b445f3d64764e49.js"> </script>

<h1 id="gallerycellswift">GalleryCell.swift</h1>

<script src="https://gist.github.com/4aca9a8cf544647d342f013293aaab6c.js"> </script>]]></content><author><name></name></author><summary type="html"><![CDATA[Résumé: Cette version permet de charger une image de manière asynchrone depuis un fichier avec Swift et une OperationQueue, vers une UICollectionViewCell.]]></summary></entry><entry><title type="html">[Competitive Programming] Pokemons</title><link href="https://www.jeyries.fr/blog/2018/11/10/primers-pokemon" rel="alternate" type="text/html" title="[Competitive Programming] Pokemons" /><published>2018-11-10T00:00:00+00:00</published><updated>2018-11-10T00:00:00+00:00</updated><id>https://www.jeyries.fr/blog/2018/11/10/primers-pokemon</id><content type="html" xml:base="https://www.jeyries.fr/blog/2018/11/10/primers-pokemon"><![CDATA[<p>PROBLEM: In the first generation of Pokemon, there are 164 different attacks. Each Pokemon can learn a number of attacks. As a Pokemon trainer, you want to be the team of 6 Pokemon whose union of attacks they can learn is maximum.</p>

<h1 id="the-problem">The problem</h1>

<p>Located here: <a href="http://primers.xyz/3">http://primers.xyz/3</a>. The website is in french, here is a quick translation :</p>

<blockquote>
  <p>Welcome to Primers, a site dedicated to algorithmic problems whose optimal solution is not achievable in a reasonable time. We must therefore design algorithms to find approximate solutions. Your goal: to do better than your competitors! :)</p>
</blockquote>

<blockquote>
  <p>PROBLEM: In the first generation of Pokemon, there are 164 different attacks. Each Pokemon can learn a number of attacks. As a Pokemon trainer, you want to be the team of 6 Pokemon whose union of attacks they can learn is maximum.</p>
</blockquote>

<p>So it is a bit like the old Google Code Jam: you execute your code locally and give back to the website your best solution, then the website gives you a ranking.</p>

<p>Regarding the Pokemon problem, my first approach was to do random hill climbing: start with an initial solution (=a team of 6 pokemon), and randomly replace one of the Pokemon with an other random one. If this yield a better score, continue to iterate with this new team. With a small Python script, I achieved a score of 104.</p>

<p>Returning on the website, I could see in the ranking table that the best score was 105. Some comments were hinting that an optimal solution could be found for this problem.</p>

<p>For sure, an optimal solution would be to enumerate all the teams that can be created with 6 Pokemons. This is called brute-forcing the problem, could it be done here ?</p>

<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" async=""></script>

<p>How many <a href="https://en.wikipedia.org/wiki/Combination">combinations</a> of 6 pokemons out of 150 are they ?</p>

<p>If the set has n elements, the number of k-combinations is equal to the binomial coefficient :</p>

\[\binom{n}{k} = \frac{n(n-1)...(n-k+1)}{k(k-1)...1}\]

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span> import scipy.misc
<span class="o">&gt;&gt;&gt;</span> scipy.misc.comb<span class="o">(</span>150, 6, <span class="nv">exact</span><span class="o">=</span>True<span class="o">)</span>
14297000725
</code></pre></div></div>

<p>So there is about 14 billions of combinations to test.If you can test 1 billion of combinations per seconds, it will take 14 seconds… Today processors are running north of 1 GHz, so it is something reachable.</p>

<p>To achieve that performance, Python was not possible, therefore I wrote a solution in C. Of course you better turn the optimisation on when doing that (-O3 for example).</p>

<p>Some colleague of mine was doubtful that it was possible to test a combination on a single CPU cycle.</p>

<p>Of course, you need more, but if coded well the inner loop (that test one combination) can take in the order of 10 instructions.</p>

<p>If only they had put a more difficult problem, for example teams of 8+ pokemons or a set of 250 different pokemons, then it would have been almost impossible to brute-force the problem …
​</p>
<h1 id="the-solution">The solution</h1>

<p>See <a href="https://github.com/jeyries/pokemon/blob/master/pokemon.c">pokemon.c</a> in my Github repository.</p>

<p>Below is the assembly produced with <code class="language-plaintext highlighter-rouge">gcc-8 -O3 -march=native</code>. GCC does a very good job here, the inner loop is straightforward : 3 OR + 3 POPCNT per test, a good x86-64 processor will be crushing through all the combinations in a few seconds …</p>

<pre><code class="language-asm">L7:
	movq	(%rdx), %rax
	movq	8(%rdx), %rsi
	movq	16(%rdx), %rcx
	orq	%r10, %rax
	orq	%r9, %rsi
	popcnt	%rax, %rax
	popcnt	%rsi, %rsi
	orq	%r8, %rcx
	addl	%esi, %eax
	popcnt	%rcx, %rcx
	addl	%ecx, %eax
	cmpl	%ebp, %eax
	jle	L6
	movb	7(%rsp), %cl
	movb	6(%rsp), %sil
	movb	$1, 4(%rsp)
	movl	%eax, %ebp
	movb	5(%rsp), %r15b
	movb	1(%rsp), %r13b
	movb	%bl, %r14b
	movb	%dil, %r12b
	movb	%cl, 3(%rsp)
	movb	%sil, 2(%rsp)
L6:
	incl	%edi
	addq	$24, %rdx
	cmpl	%r11d, %edi
	jne	L7
</code></pre>]]></content><author><name></name></author><summary type="html"><![CDATA[PROBLEM: In the first generation of Pokemon, there are 164 different attacks. Each Pokemon can learn a number of attacks. As a Pokemon trainer, you want to be the team of 6 Pokemon whose union of attacks they can learn is maximum.]]></summary></entry></feed>