tag:blogger.com,1999:blog-32499307646323856782024-03-19T22:46:20.103+01:00/dev/randRandom development thoughts by Thierry PasseronThierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.comBlogger21125tag:blogger.com,1999:blog-3249930764632385678.post-34494354812605110552013-03-01T22:03:00.000+01:002013-03-01T22:03:09.300+01:00Why I hate node-gypToday I had to install a node module of mine in a sandboxed environment (i.e. isolated from the system directories) and due to node-gyp what usually is just a matter of time turned into a nightmare.<br />
<br />
<a name='more'></a><br />
Prove me wrong, I hate node-gyp because:<br />
<ul>
<li>It is poorly documented </li>
</ul>
Where is the documentation for the binding.gyp? Seriously, just few examples ?...<br />
<br />
What I would be pleased to see is a node-gyp binding.gyp how-to for _make_ users. Other people would like to see the same kind of one to one mapping for other tools like Xcode, cmake, whatever...<br />
<ul>
<li>Counter intuitive from a Unix user point of view. </li>
</ul>
It's more or less the continuation of my first point. Where do the linker flags go ? where do the include paths go ? It's all a nightmare to find out what is the exact JSON option and also it's key path within the whole hash's organization.<br />
<ul>
<li>Inexistant help </li>
</ul>
Go ahead and type 'node-gyp' alone in a shell. It outputs this usage message:<br />
<br />
<pre>$ node-gyp
Usage: node-gyp <command><command></command> [options]
where <command></command> is one of:
- build - Invokes `make` and builds the module
- clean - Removes any generated build files and the "out" dir
- configure - Generates a Makefile for the current module
- rebuild - Runs "clean", "configure" and "build" all at once
- install - Install node development files for the specified node version.
- list - Prints a listing of the currently installed node development files
- remove - Removes the node development files for the specified version
for specific command usage and options try:
$ node-gyp <command> --help
</pre>
<br />
ok now, go ahead and try to get some specific help on build or configure commands:<br />
<br />
<pre>$ node-gyp configure --help
gyp info it worked if it ends with ok
gyp info using node-gyp@0.8.5
gyp info using node@0.8.21 | darwin | x64
gyp info spawn python
...
</pre>
<br />
<b>No help!</b> I told you... Not to say that it is <u>very unpleasant</u> to see it doing a work we didn't order.<br />
<br />
So why did I even bother to criticize this tool if I don't like it. Well first of all, I'm using node.js a lot these days and find it rather pleasing. And since this tool is kind of mandatory when it comes to deal with compiled modules I'm thinking it could be useful to yell a bit at it as it will be more and more widely used. Don't get me wrong I'm not criticizing for criticizing I'm doing it because I may be wrong so prove me wrong else I hope the developers will do the necessary changes in code and documentation so that it catches up the coolness of node.js.<br />
<br />
By the way, the versions I was using are: node-gyp@0.8.5 and node@0.8.21<br />
<br />
Cheers.<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-5473807426583491802013-03-01T17:22:00.002+01:002013-03-01T17:22:36.466+01:00One liner http server<br />
Since the day a friend of mine introduced me to nodejs, I now use it for all kind of daily stuff.<br />
<div>
Today I had to troubleshoot connections behind a firewall. This easy node one-liner helped me do that:</div>
<div>
<br /></div>
<pre>$ node -e 'require("http").createServer(function(req, res){ console.log("Got request"); res.end((new Date) + ""); }).listen(3001);'</pre>
<div>
<br /></div>
<div>
Cheers.<br />
<br /></div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-72262256148995060502013-01-31T22:24:00.000+01:002013-01-31T22:24:03.528+01:00expressjs async middlewaresDealing with async Middlewares in connect/expressjs can lead to unexpected behaviors if you don't take extra precautions.<br />
<br />
<a name='more'></a><br />
Example:
<br />
<br />
<pre>var app = express();
app.use(function (next_middleware) {
db.query(function(error, doc) {
/* do something with error and doc */
next_middleware(); //
});
});
/* Other middlewares... */
</pre>
<br />
<br />
This code could suffer from one problem. During the async db.query(), nobody will receive the emitted request events ("data" or "end" mostly) that could take place.
To circumvent this issue, we could use the "pause" module by TJ Holowaychuk which saves the stream's emitted "data" and "end" events and replay them on resume().
The refactored code would look something like this:
<br />
<br />
<pre>var app = express();
app.use(function (next_middleware) {
var pause = require('pause')(req); // Pause the receiving of events for req
db.query(function(error, doc) {
/* do something with error and doc */
next_middleware();
pause.resume(); // Replay events
});
});
/* Other middlewares... */
</pre>
<br />
<br />
It is worth to note that connect/expressjs use it internally for example in the static middleware.<br />
<br />
Cheers.<br />
<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-72302133490784075382013-01-12T10:07:00.005+01:002013-01-12T10:09:26.732+01:00Snippets in JSMainly useful to me, but can also be found useful by others, I'll put here some of the JS snippets I don't want to loose. Some are written by me, some may be found on the internet in which case I'll try my best to give credit to the author(s). This document should be a living document. Feel free to comment and submit new snippets in your comments. Cheers.<br />
<br />
<a name='more'></a><br />
<h4>
Snippet #1 [Browser]</h4>
<pre>/*
Get the JSON params of the current script
Example markup:
<script src="path/to/script.js#{a:1,b:2}"></script>
<script>
var params = getScriptJSONParams("path/to/script.js");
// => {a:1, b:2}
<script>
*/
function getScriptJSONParams(script_name_regexp, doc) {
var scripts = doc.getElementsByTagName("script")
, n = scripts.length;
if (typeof script_name_regexp === 'string') script_name_regexp = new RegExp(script_name_regexp);
while (n--) {
var script = scripts[n]
if (script_name_regexp.test(script.src)) return JSON.parse(script.src.split('#')[1]);
}
}
</pre>
<br />
<h4>
Snippet #2 [Browser] found on the net (don't remember where :/)</h4>
<pre>/*
JSON _parse_ when "JSON" lib is not available in a browser
*/
function evil(str) { return eval("(" + str + ")") }
</pre>
<br />
<h4>
Snippet #3 [Browser|Nodejs]</h4>
<pre>/*
My personal commented interpretation of John Resig's class for javascript
Highly based on:
Simple JavaScript Inheritance By John Resig http://ejohn.org/
MIT Licensed.
http://ejohn.org/blog/simple-javascript-inheritance/
Example usage:
var Foo = Class.extend({ init: function(n) { this.foo = n }, hello: function(){ return "Hello World!" } });
var Bar = Foo.extend({ init: function () {
this.bar = "Bar";
Bar.Super(this, 'init', 4); // It is a call to the Super-prototype, and is a shortcut for:
// Foo.prototype.init.call(this, 4)
}});
console.log(new Bar);
// { bar: 'Bar', foo: 4 }
console.log((new Bar).hello());
// Hello World!
*/
!function(name, def) {
if (typeof define === 'function') define(def);
else if (typeof module !== 'undefined') module.exports = def();
else this[name] = def()
}('Class', function () {
var shouldInit = false; // Exterior to the Class.Extend because it needs to be controlled for Every Class object
// The base Class implementation (does nothing)
var Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype; // The Super prototype
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
shouldInit = false;
var prototype = new this(); // The new prototype Object
shouldInit = true;
// Copy the properties over onto the new prototype
for (var name in prop) { prototype[name] = prop[name]; } // Feeding the new prototype Object with the argument's Object
// The dummy class constructor
function Klass() {
// All construction is actually done in the init method
if (shouldInit && this.init) this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Klass.prototype = prototype;
// Create a tool Super() function to access the Super prototype
Klass.Super = function (self, prop) {
if (arguments.length < 2) return _super;
return (typeof _super[prop] === 'function') ? _super[prop].apply(self, [].slice.call(arguments, 2)) : _super[prop];
}
// Enforce the constructor to be what we expect
Klass.prototype.constructor = Klass;
// And make this class extendable
Klass.extend = arguments.callee;
return Klass;
};
return Class;
});
</pre>
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-72303593363634953552013-01-10T20:50:00.004+01:002013-01-10T23:07:18.576+01:00Nodejs in admin landToday I needed to install a node app on a remote server which uses monit as monitoring facility.<br />
<br />
Sending the app over to the remote host was done using the 'git clone' command.<br />
But now that the app is in place I need to monitor it.<br />
<br />
<a name='more'></a><br />
Oh and I forgot to tell you that this app (a very lightweight and efficient app obviously ;) is ment to be deployed many times on the same server in order to serve the clients of some of my customers in an independent manner. Hence, I have to create multiple monit configuration files for each of the node apps to be monitored but they will all look the same.<br />
<br />
So what I needed was a monitrc template file that I could render with different settings. First I remembered that I already did this kind of stuff when I was a Unix admin ... in perl ... it was a long time ago now. But wouldn't it be wonderful to use node for this also?<br />
<br />
Yes, let's! :D<br />
<br />
<pre>#!/usr/bin/env node
/*
Output the monitrc of this app
Usage:
OPTIONS='{<bin-dir>"port":<port-number>, ...<port-number>}' ./monitrc.sh
*/
var options = JSON.parse(process.env.OPTIONS || "null") || {};
options.port = options.port || 3000;
options.dir = options.dir || __dirname;
console.log(require('ejs').compile([
'check process node with pidfile "<%- dir %>/../tmp/app.pid"',
' start program = "/usr/bin/env PORT=<%- port %> <%- dir %>/apprc.sh start"',
' stop program = "<%- dir %>/apprc.sh stop"',
' if failed port <%- port %> protocol HTTP',
' request /',
' with timeout 10 seconds',
' then restart'
].join("\n"))(options));
</port-number></bin-dir></pre>
Notice that dir is the dirname of the script because the script is installed in ./bin of the app directory. As you can see I use 'EJS' to manage the template part because EJS is a global module used in the apps. The apprc.sh script is a standard start/stop/status rc script which starts node.js.<br />
<br />
How wonderful! I now not only use javascript on the client side, on the server side but also on the admin side...<br />
<b>One javascript to rule them all :)</b><br />
<br />
Cheers.<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-52394264674825053922013-01-09T20:31:00.001+01:002013-01-09T20:41:47.514+01:00iOS Provisioning Profile demystified<div>
Ever had to create a new provisioning profile for an iOS app? Or had to deal with not working certificates? In this post - a living document - I will try to explain some of the concepts of Apple's code signing workflow which despite the amount of resources and tech-notes has caused me so many headaches.</div>
<div>
<br />
<a name='more'></a></div>
<span style="font-size: x-large;"><b>Code-signing</b></span><br />
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>Why would you need to code-sign? </b></span></div>
<div>
<br /></div>
<div>
In order to provide a relationship of trust between the developer and Apple, it is necessary to know who is who. So the code-signing is used to match a Developer, an Organization and an Application (code).</div>
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>What is an AppID?</b></span></div>
<div>
<br /></div>
<div>
The AppID is an important asset of the code-signing process. It must be unique and identifies a unique Application. You will later use this AppID to create provisioning profiles.</div>
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>What is a provisioning profile?</b></span></div>
<div>
<br /></div>
<div>
A provisioning profile associates an Application and a Developer/Organization. That is it is the association of a Certificate and an AppID.</div>
<div>
You need to create a new provisioning profile for each application that needs to be distributed. The provisioning profile has an expiration date after which it is no longer valid. For what I have seen the distribution profile is only worth when submitting to the AppStore. I mean If you submitted an Application and the profile expires, the Application is still selling and nothing will happen. You may delete a used, unused, or expired provisioning profile from the portal with no edge effect. You will need to create a new provisioning profile to submit a new Application or an update to an already submitted Application.</div>
<div>
<br /></div>
<div>
This is where the importance of the AppID really shows. You can create/remove profiles but cannot remove AppIDs. I guess that Apple didn't want to manage orphan Apps and too much user issues so they may have decided to forbid AppIDs removal. Thus, when you create an AppID, take your time to re-read many times your inputs because I can tell you ... you'll be stuck with this AppID for the rest of your Developer/Organization's Account life.</div>
<div>
<br /></div>
<div>
One wise developer has made a safari/chrome extension that will allow you to darken AppIDs in the portal. (<a href="https://github.com/simonwhitaker/app-id-sanity" target="_blank">You can find it here on github</a>) It's by far the best we can do.</div>
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>Concerning Certificates</b></span></div>
<div>
<br /></div>
<div>
The certificates are the piece of code-bits that identify a developer and/or an organization. You create them by requesting them from an authority. In our case the Authority is Apple. You first create a Certificate Signing Request using the keychain for example. Then you transfer this request file to Apple's servers and get back a certificate if all is well. </div>
<div>
<br /></div>
<div>
There are two main certificates you will deal with as a iOS developer. The development certificate and the distribution certificate. </div>
<div>
<br /></div>
<div>
Ye be warned! If you don't backup certificates and for example you reinstall the OS, you will need to recreate them and since each provisioning profile has a reference to a certificate, you will need to recreate each profiles.</div>
<div>
<br /></div>
<div>
But, except for the extra work you will have to do, there is no harm, you CAN safely (as far as I can tell from my own experience...;) recreate them. The Applications already on the AppStore will not get hurt. But you will have to recreate the profiles, delete the old ones etc ... </div>
<div>
<br /></div>
<div>
There are other certificates you may have to create. For example, the push certificates etc ... The very same remarks apply to them.</div>
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>Push certificates</b></span></div>
<div>
<br /></div>
<div>
You have an Application with certificates and all is well and you'd like to add some feedback functionality through push notifications for your users. Great!</div>
<div>
So basically there is no difficulty with this. You go to the Provisioning Portal > AppID > your AppID > update , check the "enable push notification" and with a certificate signing request you create the development and production push certificates. Download each certificate and double click them, Xcode will install them.</div>
<div>
<br /></div>
<div>
There is one pitfall here. Once you updated the AppID, the already existing provisioning profiles are not updated to take into account the enabled push notification. So you need to update a profile or create a new one, re-download it from Apple's and install it on your Mac. Then, remove the old one and select the new profile in the XCode build settings.</div>
<div>
<br /></div>
<div>
To check if an Application has a profile with push notification enabled you run this in a terminal:</div>
<div>
<br /></div>
<pre>$ codesign -dvvvv --entitlements - path/to/<YourAppName>.app
</pre>
<div>
<br /></div>
<div>
The output should mention an aps-environment. If not, it's a wrong profile.</div>
<div>
<br />
<br /></div>
<div>
<span style="font-size: large;"><b>Pem cert and key</b></span></div>
<div>
<br /></div>
<div>
On the server-side, you need to have a pem certificate in order to establish the ssl connection to Apple's push gateway. Here is how I do it:</div>
<div>
<br /></div>
<div>
In Keychain > Certificates > search 'push' (in the upper-right search box)</div>
<div>
<br /></div>
<div>
Select the certificate you want to export in the list (There MUST be a a gray triangle denoting a embedded key, else the certificate is missing it's key which is needed!) > Export "Certificates.p12"</div>
<div>
<br /></div>
<div>
Now, in the terminal:</div>
<div>
<br /></div>
<pre>$ openssl pkcs12 -clcerts -nokeys -out cert.pem -in Certificates.p12
$ openssl pkcs12 -nocerts -out key.pem -in Certificates.p12
</pre>
<div>
<br /></div>
<div>
This has created the cert.pem and key.pem</div>
<div>
<br /></div>
<div>
To remove the password from the key:</div>
<div>
<br /></div>
<pre>$ openssl rsa -in key.pem -out key.nopass.pem
</pre>
<div>
<br /></div>
<div>
If you indeed need a combined pem with certificate and key:</div>
<div>
<br /></div>
<pre>$ cat cert.pem key.nopass.pem > identity.pem
</pre>
<div>
<br /></div>
<div>
To be able to push a notification to Apple I have created a nodejs module named node_apns which is also available on my <a href="https://github.com/Orion98MC/node_apns" target="_blank">github profile</a>. </div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<span style="font-size: large;"><b>Troubleshooting</b></span></div>
<div>
<br /></div>
<div>
You should check <a href="https://developer.apple.com/library/ios/#technotes/tn2250/_index.html#//apple_ref/doc/uid/DTS40009933-CH1-TNTAG24" target="_blank">this document</a> from Apple</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Cheers.</div>
<div>
<br /></div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-34726248932026457112013-01-05T10:24:00.000+01:002013-01-05T10:24:37.718+01:00Brewing NodejsLately I ran into an issue while doing a '<i>brew upgrade</i>' on my mac. Homebrew upgraded nodejs from 0.8.4 to 0.8.16. It was a very bad time for me to do this update since I was pretty much in the middle of a very important nodejs development and all the setup was working well enough... In fact I was willing to do a '<i>update</i>' of brew and ended up typing '<i>upgrade</i>' ... !#?@<br />
<br />
<a name='more'></a><br />
Anyways, at the end of the whole upgrade process I took a time to re-read the operation log and hunt for errors or warning just in case. How wise! node and npm where not completely installed, the links in /usr/local/bin where not made. See:<br />
<br />
<pre>Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
You can try again using `brew link node'
</pre>
<br />
So I tried the recommended command:<br />
<br />
<pre>$ brew link node
Linking /usr/local/Cellar/node/0.8.16... Warning: Could not link node. Unlinking...
Error: Could not symlink file: /usr/local/Cellar/node/0.8.16/bin/npm
Target /usr/local/bin/npm already exists. You may need to delete it.
To force the link and delete this file, do:
brew link --overwrite formula_name
To list all files that would be deleted:
brew link --overwrite --dry-run formula_name
</pre>
<br />
<span style="background-color: red;"><b>Tadaaaa!</b></span><br />
<br />
<pre>$ brew link --overwrite node
Linking /usr/local/Cellar/node/0.8.16... Warning: Could not link node. Unlinking...
Error: Permission denied - /usr/local/lib/node_modules/npm/node_modules/read-package-json/README.md
</pre>
<br />
<span style="background-color: red;"><b>Fu@@!</b></span> ... (Why didn't I press CTRL-C when I noticed I typed a 'upgrade' instead of 'update'.)<br />
<br />
<pre>$ sudo brew link node
Password:
Error: Cowardly refusing to `sudo brew link'
You can use brew with sudo, but only if the brew executable is owned by root.
However, this is both not recommended and completely unsupported so do so at
your own risk.
</pre>
<br />
Thanks Max ;) that was dumb anyways...<br />
<br />
<u>From this point I entered hardcore make-it-work-by-any-mean mode! So please don't flame me :)</u><br />
<br />
Here is what I did. I can tell you right away that it worked and probably can help you if you ever get yourself in the same messy state I was but it may not be the preferred way to solve this. So if you have a better way I'm all ears in the comments.<br />
<br />
<ul>
<li>First I notices that the /usr/local/lib/node_modules was the global modules' dir of the 0.8.4 version. So I moved it to node_modules.0.8.4.</li>
<li>Then I redid the '<span style="font-family: Helvetica;"><i>brew link --overwrite node</i></span>' and It worked!</li>
<li>Then I checked '<i>which</i>' node and npm ... Ok my PATH was still good!</li>
<li>Then I checked node and npm versions ... Ok it's the new ones!</li>
<li>Then I tried to reinstall all my required global modules with npm ... Ok!</li>
<li>Then I ran 'node' and required one of the installed modules... <span style="background-color: red;"><b>Not Ok</b></span>!</li>
</ul>
<br />
The module was not found although I could see it in the output log of 'npm list -g'<br />
<br />
<span style="background-color: orange;"> ! </span> I noticed that the node_modules dir as reported by npm was now /usr/local/share/npm/lib/node_modules (<b>Was it changed by the new formula?</b>)<br />
<br />
So I updated my NODE_PATH environment variable to this path. And now it's working!<br />
<br />
Cheers.<br />
<br />
<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-22223632344545063282012-12-21T14:00:00.000+01:002012-12-26T19:54:14.947+01:00Coding tip: readability first!In this 'Coding tip' I'll introduce you to one of the most sustainable coding tip of mine IMO. You may or may not agree with me but this has proven to be a valuable tip for me in terms of coding maintainability.<br />
<br />
This one tip is was I call 'put material where the work needs to be done'. It is the opposite of offshoring :)<br />
<br />
<br />
<a name='more'></a><h3>
Rule:</h3>
Put the code where it is needed. If a code is needed in more than one place put it in a reusable form (function/method/...). Use code-folding to un-clutter when needed.<br />
<br />
<span style="color: red;">Example in ObjC <b><u>not</u></b> applying this rule</span>:<br />
<br />
<pre>- (void)viewDidLoad {
[super viewDidLoad];
[self setupImageView];
[self setupTitleView];
[self setupButton];
}
</pre>
<br />
<span style="color: #38761d;">Example in ObjC applying this rule</span>:<br />
<br />
<pre>- (void)viewDidLoad {
[super viewDidLoad];
// Setup the ImageView
UIImageView *imageView = [[[UIImageView alloc]init]autorelease];
/*
...
configure the imageView
...
*/
[self.view addSubview:imageView];
// Setup the TitleView
UILabel *titleView = [[[UILabel alloc]init]autorelease];
/*
...
configure the titleView
...
*/
[self.view addSubview:titleView];
// Setup the Button
UIButton *button = [[[UIButton alloc]init]autorelease];
/*
...
configure the button
...
*/
[self.view addSubview:button];
}
</pre>
<br />
<h4>
Discussion:</h4>
You may find the first solution more readable but it is only because it hides most of the work in secondary methods.<br />
<br />
The point of this tip is to avoid the creation of sub methods/functions just to tidy up a long block. In fact this will complicate the reading and will also clutter the namespace.<br />
<br />
The second example (which use this tip) is what I prefer since it allows one to find everything it needs in one place. It is even possible to get the same level of low verbosity as in the first example with the use of code folding that most code editors provide. To do so, I usually put each sub-parts inside its own block (using curly brackets in C)<br />
<br />
<h4>
Example of foldable sub-part code (notice the curly brackets):</h4>
<pre>// Setup the ImageView
{
UIImageView *imageView = [[[UIImageView alloc]init]autorelease];
/*
...
configure the imageView
...
*/
[self.view addSubview:imageView];
}
</pre>
<br />
<h4>
Folded code result:</h4>
<pre>- (void)viewDidLoad {
[super viewDidLoad];
// Setup the ImageView
{<span style="background-color: #ffe599;">...</span>}
// Setup the TitleView
{<span style="background-color: #ffe599;">...</span>}
// Setup the Button
{<span style="background-color: #ffe599;">...</span>}
}
</pre>
<div>
<br />
<br />
Now you see how readable your code can be. At any moment you may see the whole code or if you wish you can fold every blocks and unfold just one to get inside a specific part.<br />
<br />
My personal rating for this tip is:<br />
<br />
<b>Performance 2/5</b><br />
<b>Readability 5/5</b><br />
<b>Sustainability 4/5</b><br />
<br /></div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-60525386152478162982012-12-21T12:46:00.001+01:002012-12-21T13:59:13.687+01:00Coding tip: early exitIn this series of 'coding tips' articles I will show you some of the lesson learned tips I am using on a daily basis during development. They are general purpose tips which can easily be adapted to most development languages.<br />
<br />
The first one is what I call <i><b>Early exit</b>. </i><br />
<i><br /></i>
<br />
<br />
<a name='more'></a><br />
<h3>
Early exit:</h3>
<u>Put the exit (or return) conditions on the top of a code block.</u><br />
<h4>
</h4>
<h4>
Example in C:</h4>
<pre>{
if (error) { // Early exit when 'error'
fprintf(stderr, "Error: %s", error.message);
return;
}
/*
Other statements
*/
}
</pre>
<br />
It is really straightforward and helps you identify shortest execution paths. Plus it helps getting rid of if/then/else blocks and improves readability.<br />
<br />
So my personal rating for this coding tip is:<br />
<br />
<b>Performance 2/5</b><br />
<b>Readability 4/5</b><br />
<b>Sustainability 3/5</b><br />
<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-33786170889201423422012-12-01T16:28:00.002+01:002013-07-12T08:15:15.095+02:00Push Notifications to Apple, made... almost reliable!For one of my projects I need to push informations to iOS devices. Apple has made a great doc on how to implement push notifications but as a matter of fact the ideal world of the documentation is not the one most developers experiment when dealing with push notifications to Apple's servers.<br />
<br />
The thing that bothers most of us is the lack, or at least the manner, of feedback when a notification is sent. That is asynchro-loosly ;)<br />
<br />
<a name='more'></a><br />
I understand that it is better from Apple's point of view to manage the feedbacks asynchronously but it can be a pain in the *** when you have to deal with it in order to provide a reliable service to your customers. But Hey! Apple stated it's not a reliable communication stream... Ye be warned!<br />
<br />
The thing that puzzles me most is not that the communication between Apple and the device is a best effort kind of deal. Fine! What is really unpleasant is that the communication between the service provider and Apple is also very un-reliable with regards to the current spec.<br />
<br />
When one pushes to Apple a valid payload, at least from the service provider point of view, it cannot be sure that the notification would even pass the first sanity filter at Apple. One has to keep in mind that this notification payload could be rejected later. And as stated by Apple's spec, in case of a bad payload the connection will be silently closed after sending a error-response. Since this response is asynchronous, you may have sent other payloads between the bad payload and the arrival of the error response. Moreover, Apple does not provide any max delay between a received payload and the error-response. So basically they say they could respond later on that the payload sent before (a long time ago?) was indeed invalid and that they trashed all other payloads since then.<br />
<br />
<strike>From a communication point of view, this is a lack of bandwidth.</strike> From the service provider point of view it's a lack of consistency.<br />
<br />
<b><u>EDIT (July 2013):</u></b><br />
<span style="color: #274e13;">As a matter of fact, it seams to be stated by Apple on it's doc that this kind of behavior is general to socket services and that this async behavior is designed for best performances. However, I must confess that my understanding of this topic has evolved a bit and I am now convinced that you really can deal with it without too much trouble. See the end of the document.</span><br />
<h4>
<strike>
Plan A: "Apple, please..!" </strike></h4>
<h3>
Plan B.</h3>
<div>
Ok let's now focus on one possible solution at the service provider level.</div>
<div>
<br /></div>
<div>
It assumes all notifications are enhanced notifications (with UID) and also that notifications' UID are incremental (1, 2, 3,...etc..)<br />
<br />
<h4>
Connector pseudo-code</h4>
(This code is responsible for managing the connection to Apple and sending notifications)<br />
When a notification has to be sent<br />
- make a connection to Apple if needed<br />
- send the notification<br />
<br />
When an error is reported by Apple<br />
- emit a 'payload-error' with the UID of the notification<br />
<br />
<h4>
Consumer pseudo-code</h4>
</div>
<div>
While notifications have to be sent </div>
<div>
- send notification to Apple (via Connector)</div>
<div>
- emit a 'sent' message with the notification as argument</div>
<div>
<br /></div>
<div>
<h4>
Producer pseudo-code</h4>
</div>
<div>
- maintain a unconfirmed notifications list (default: empty list)<br />
<br />
When a 'sent' is emitted<br />
- add the notification to the unconfirmed list</div>
<div>
<br /></div>
<div>
While allowed to submit AND new notifications have to be sent </div>
<div>
- check notification validity</div>
<div>
- submit notification to the Consumer queue</div>
<div>
<br /></div>
<div>
When an 'payload-error' is emitted</div>
<div>
- Disallow Producer's submissions</div>
<div>
- Process the error (black list tokens etc... for validity check in Producer submission loop)</div>
<div>
- Remove the unconfirmed notifications with UID lesser or equal to the erroneous UID </div>
<div>
- Re-submit to the Producer unconfirmed notifications with UID greater that the erroneous UID so that they will be re-submitted to the Consumer after being checked for validity</div>
<div>
- Allow Producer's submissions</div>
<div>
<br />
If no more notifications need to be submitted by the Producer for a PERIOD seconds<br />
- clear unconfirmed list<br />
- report to the customer that it's all done!</div>
<div>
<br />
<h3>
How does it work? </h3>
</div>
<div>
When a notification needs to be sent it follows this workflow:</div>
<div>
<br /></div>
<div>
Producer -> Consumer -> Connector</div>
<div>
<br /></div>
<div>
The Producer submits a valid notification to the Consumer.</div>
<div>
When the Consumer did send the notification via the Connector it sends a 'sent' message, the Producer adds the notification to its unconfirmed list.</div>
<div>
<br /></div>
<div>
When an 'payload-error' message happens, the notifications prior to the erroneous notification are removed from the unconfirmed list, the remaining notifications are re-processed by the Producer.</div>
<div>
<br /></div>
<div>
When all of the Producer's notifications have been sent and enough time has passed (?) then, consider that Apple has accepted all the notifications, clear the unconfirmed list.</div>
<div>
<br /></div>
<div>
<u>Rem</u>: there may be more than one Producer, each of which will maintain its own set of unconfirmed notifications.</div>
<div>
<br /></div>
<h3>
Final word</h3>
<div>
I have no open source code implementing this solution to show you yet, but, I plan to release a nodejs example. Know that it uses node_apns a node package of mine handling On demand Push notification connections. You may find it <a href="https://github.com/Orion98MC/node_apns" target="_blank">here on may github profile</a></div>
<div>
Although it may not be the best method it has proven to be reliable for me. Anyways, I'm open to any suggestions. Feel free to comment.</div>
<div>
<br />
<br />
<b><u>Edited (July 2013)</u></b><br />
<b><br /></b><span style="color: #274e13;">
I have now a slightly reworked open source code to show you.</span><br />
<span style="color: #274e13;">You may find it on my github page <a href="https://github.com/Orion98MC/node_apns" target="_blank">here</a>.</span><br />
<span style="color: #274e13;">It has been added to the node_apns module as a service. The key object is services.Notifier. It takes care of everything and makes notifications delivery very robust and efficient.</span><br />
<span style="color: #274e13;"><br /></span>
<span style="color: #274e13;">One thing to note though, you should always set the expiry of notifications (services.Notifier uses enhanced notifications to make reliable deliveries) to an appropriate value so that the devices that do not have working persistent connexion to the push service at the moment of the send will get the chance to cache it later when they rebuild their connexion.</span></div>
<div>
<br />
Cheers<br />
<br />
<br /></div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com4tag:blogger.com,1999:blog-3249930764632385678.post-20591135534776028442012-11-15T15:25:00.000+01:002012-11-15T15:32:21.304+01:00expressjs with ... no layout ?!Yesterday, I was working on a backoffice web application I will be releasing soon for one of my iOS projects. This web application is powered by node.js. I love node.js.<br />
When it comes to creating web apps with nodejs I first had tried to managed all the routing aspects and stuff myself but lately I crossed expressjs.<br />
expressjs is not as overbloated as most web frameworks in my opinion. I like simple stuff because when it comes to debug or extend the thing it's always easier. And it happened, I had to get my hands into expressjs because it appears that the layout abilities were removed from expressjs since 3.0.<br />
<br />
The solution they (the developers) give is to have two separate files which you will include in any view before and after your custom content. Something like (with ejs engine):<br />
<br />
<pre><%- include 'top.ejs' %>
my custom content
<%- include 'bottom.ejs' %>
</pre>
<br />
As a former ruby on rails developer, I am used to partials and layouts, so this workaround is rather repelling to me.<br />
<br />
<a name='more'></a><br />
<br />
To find or build a decent workaround I would have to hunt the res.render() method. So I dove in express.js and found that the 'res' of any middleware or route handler is setup in the file response.js of the framework, then I found that the response is in fact an object with the prototype of http.ServerResponse<br />
<br />
<pre>var res = module.exports = {
__proto__: http.ServerResponse.prototype
};
</pre>
<br />
Interesting!<br />
<br />
Now if you scroll to line 695 (of response.js) you'll see that res.render() calls app.render()<br />
<br />
<pre>app.render(view, options, fn);
</pre>
<br />
Now if you switch to the application.js file, around line 454 there is the app.render() method. One thing is worth to note there, the template 'name' to render is expended to it's path by the use of the View object which is not accessible from outside. What this means is that we should use app.render whenever possible to render a template and not try to do it by hand because we would loose all the path resolution bound to the express object.<br />
<br />
<h3>
Let's do it!</h3>
<pre>http.ServerResponse.prototype.renderInLayout = function (template, options, cb) {
/* do stuff */
}
</pre>
<br />
Now we need to access the express instance from our function. It's easy since express stores 'req' in the 'res' and 'req' stores 'app' if you follow me ;)<br />
<br />
<pre>var app = this.req.app;
</pre>
<br />
And so, the whole function becomes:<br />
<br />
<pre>http.ServerResponse.prototype.renderInLayout = function (template, options, cb) {
var
self = this
, app = this.req.app
;
app.render(template, options || {}, function (error, result) {
if (error) { /* handle error */ }
app.render(layout, { yield: result }, cb);
});
}
http.ServerResponse.prototype.renderInLayout = render;
</pre>
<br />
Now I can write a simple layout like:<br />
<br />
<pre><html>
<body>
<%- yield %>
</body>
</html>
</pre>
<br />
And use my renderInLayout like this:<br />
<br />
<pre>res.renderInLayout('devices', {
title: 'Devices list',
devices: result
});
</pre>
<br />
<br />
You may find the full code with a bit of sugar on github: <a href="https://github.com/Orion98MC/express_layout" target="_blank">https://github.com/Orion98MC/express_layout</a><br />
<br />
The beauty of this is that it should work for any engine. Of course, it's a very simplistic implementation, one could add contentFor and stuff ... But that's what I was looking for at the moment. Feel free to fork!<br />
<br />
Cheers.<br />
<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-75767701367279993942012-10-06T17:29:00.000+02:002013-01-05T11:36:27.530+01:00Yet an other Objective-C block for funYou know what, I could not live without blocks... It's sad but true.<br />
<br />
<h3>
Action blocks!</h3>
If you read all my previous block posts you now know how to use a <a href="http://orion98mc.blogspot.com/2012/08/objective-c-blocks-for-fun.html">block in a NSTimer</a>. It's pretty neat and few people did take the time to say so in the comments which is great!<br />
<br />
Now let's push the principle in the UI land. How about a block as target/action for any UIControl subclass ? That would be great not to have to write an other delegate method...<br />
<br />
<a name='more'></a><h3>
Example</h3>
<div>
Instead of this ...</div>
<div>
<br /></div>
<pre>- (void)viewDidLoad {
...
UISegmentedControl *rightButtons = [[[UISegmentedControl alloc]initWithItems:@[UIBarButtonItemSearchImage, UIBarButtonItemSortbyImage]]autorelease];
[rightButtons addTarget:self action:@selector(rightButtonPressed:) forControlEvents:UIControlEventValueChanged];
...
}
- (void)rightButtonPressed:(id)sender {
/* Do this */
}
</pre>
<div>
<br /></div>
<div>
I prefer to write ...</div>
<div>
<br /></div>
<pre>__block UISegmentedControl *rightButtons = [[[UISegmentedControl alloc]initWithItems:@[UIBarButtonItemSearchImage, UIBarButtonItemSortbyImage]]autorelease];
id handler = [NSBlockOperation blockOperationWithBlock:^{ /* Do this */ }];
[rightButtons.layer setValue:handler forKey:@"_handler"]; // Retain the handler
[rightButtons addTarget:handler action:@selector(main) forControlEvents:UIControlEventValueChanged];
</pre>
<br />
Since the UIResponder addTarget:action:forControlEvents: does not retain its target (unlike NSTimer), we store the block operation in the layer (every UI element has a layer). The main selector will run the block.<br />
<br />
Now you may not find it as thrilling as the NSTimer trick but it still helps the reader figure the whole execution flow without requiring too much read-jumps.<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-51640361811885580822012-09-27T00:32:00.002+02:002013-01-05T11:37:21.160+01:00Easy Updating of UITableView-s When it comes to update a UITableView you have two choices. Either you reload the whole UITableView by sending a reload message or you can do differential updates by inserting, deleting and reloading rows with changed contents.<br />
<br />
However it may be somehow difficult to always succeed in differential updates. Very often a UITableView assertion error falls down. And it can become very confusing with many sections etc...<br />
<br />
<a name='more'></a><br />
<h3>
Avoiding UITableView Assertions Errors</h3>
<div>
To avoid, these assertions errors, we have to be extra careful and:</div>
<div>
<ul>
<li>Avoid changing the data source out of the main thread.</li>
</ul>
</div>
<div>
I'm not saying "don't" but avoid because you may end up with concurrent updates.<br />
You may process and compute the updates on an other thread but the data source should be changed just right before the tableView updates. I usually do the computation on an other thread and swap (or commit) the data source at update time on the main thread.</div>
<div>
<ul>
<li>Group changes (reloads/deletes/inserts) within a -[UITableView beginUpdates] / -[UITableView endUpdates] block</li>
</ul>
</div>
<div>
The reason for this is that when a an update is processed by the UITableView, it does a bit of consistency checking by making a snapshot of how many entries there were before and how many there are after. If you insert new rows, the total rows count must increase accordingly. And if you remove rows the count must decrease.<br />
<br />
So if you need to do both deletes and inserts in the same tableview update, you must proceed like this:</div>
<div>
<br /></div>
<pre>[datasource commitUpdates];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:deleteIndexPaths withRowAnimation:UITableViewRowAnimation...];
[tableView insertRowsAtIndexPaths:insertIndexPaths withRowAnimation:UITableViewRowAnimation...];
[tableView endUpdates];
</pre>
<br />
<h3>
Complex UITableView-s</h3>
<div>
Your project may require a big UITableView with many sections. It can be difficult to manage different data sources for each sections not to say that the UITableViewDataSource methods for cell creation and others may look very very complex with a lot of conditions or switches etc...</div>
<h3>
</h3>
<h3>
Enters SmartGroups</h3>
<div>
So I made these two classes MCCSmartGroup and MCCSmartGroupManager which are very easy to use and don't require much to learn. You may find them on my github profile. These class provide a good solution to this problem. They allow a much clearer implementation (with blocks!;) and also manage the updating without any additional code from yourself.</div>
<h4>
</h4>
<h4>
Creating a SmartGroup</h4>
<div>
A SmartGroup in my terminology is a group of rows that depends on same data source. The smart group knows how to fetch it's data and also knows how to present itself by returning a view for each row it owns (it's smart huh?). So basically, the SmartGroup is an Object that makes the link between a dataSource and a set of views. When the dataSource is updated, you may send a reload message to the SmartGroup so that it can analyze the differences and create views accordingly.</div>
<div>
<br /></div>
<div>
Example:</div>
<pre>MCCSmartGroup *smartGroup = [[[MCCSmartGroup alloc]init]autorelease];
smartGroup.dataBlock = ^NSArray *{
return self.names;
};
smartGroup.viewBlock = ^UIView *(NSInteger index, NSString *name) {
return /* a UIView for this index and name */;
};
</pre>
<div>
<br /></div>
<div>
For the sake of this example, let's pretend that we display a list of names and that there is a NSMutableArray ivar containing names.<br />
<br />
In a UITableView context, the SmartGroup is a section. Each row is a UITableViewCell returned by the smartGroup from its viewBlock.<br />
<br />
Example in a UITableView context:</div>
<div>
<pre>smartGroup.title = @"Names"; // Section title
smartGroup.viewBlock = ^UITableViewCell *(NSInteger index, NSString *name) {
static NSString *identifier = @"identifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier1]autorelease];
}
cell.textLabel.text = name;
return cell;
};
</pre>
<br /></div>
<div>
As you can see, nothing special here it's the basic UITableView data source cell creation method in a block.<br />
<br />
Since we want to add this SmartGroup to the UITableView we now need to introduce the MCCSmartGroupManager which manages SmartGroups.<br />
You add SmartGroups to it. Then you set the manager as the dataSource of the UITableView and your all set.<br />
<br />
Example:</div>
<pre>self.manager = [[[MCCSmartGroupManager alloc]init]autorelease];
[manager addSmartGroup:smartGroup inTableView:tableView];
tableView.dataSource = manager;
</pre>
<div>
<br />
This does two things. First it added the SmartGroup to the manager object and then told the manager that it is in a UITableView context. The manager now knows how to insert/delete/reload rows when the SmartGroup is updated. From now on, you will never have to worry about rows being added, or removed or reloaded or section appearing or disappearing, all this will be handled by the manager.<br />
<br />
Now all that is left to do is to trigger the SmartGroup update when the dataSource of the SmartGroup changes. For example, when a new name pops in. You have many options. You can either store a reference to the SmartGroup in a controller ivar and then send processUpdate message to it, or you can register for a particular update notification like this:<br />
<br /></div>
<pre>[[NSNotificationCenter defaultCenter]addObserverForName:@"updateNames" object:nil queue:aQueue usingBlock:^(NSNotification *note) {
[smartGroup processUpdates];
}];
</pre>
<br />
Now when you update the data source of this SmartGroup (because you added few names and removed few others) you just need to send this @"updateNames" notification and the rest of the UITableView updating is automatically handled for you. Rows will be inserted, deleted, reloaded... sections will be inserted or removed ... all with animation!<br />
<br />
Note: You don't need to send the processUpdates message on the main thread since the MCCSmartGroupManager will dispatch_async to the main queue the tableView updates.<br />
<br />
Be sure to check these class on my github profile <a href="https://github.com/Orion98MC/MCCSmartGroups" target="_blank">here</a>.<br />
<br />
Cheers.<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-88277343157774422702012-09-20T23:16:00.000+02:002012-09-25T15:35:45.280+02:00Seamless downloads with MCCURLConnectionI already told you about this class of mine which is a queued NSURLConnection with block delegates. I use it as a ASIHTTPRequest replacement. Now it's been updated (<a href="https://github.com/Orion98MC/MCCURLConnection">here</a>) and there are new features I'm going to show you.<br />
<br />
<a name='more'></a><br />
<h3>
Hands on Lab</h3>
Say you want to fetch images from the internet in your iOS application. Let's see how we can manage to do that in very few lines with the MCCURLConnection.<br />
<br />
First get the class files from github either by cloning the repository or by getting the zip file.<br />
<br />
Then, add the 2 files to your project using the xcode "add files" menu.<br />
<br />
Now, let's pretend we are in the middle of a method in your controller code that needs to load an image. The first thing to do is to add the #import directive to your view controller class implementation file. Then we will fetch the image, something like this:<br />
<br />
<br />
<pre class="prettyprint">#import "MCCURLConnection.h"
- (void)viewWillAppear:(BOOL)animated {
// Fetch the image
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.myimages.com/my/image.jpg"]];
[[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
/* Do stuff with the completed connection object */
}];
}
</pre>
<br />
Now, what can we do in the callback block, with this connection object? Few things.<br />
<ul>
<li>Check the error code if any</li>
</ul>
<pre class="prettyprint"> [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
if (connection.error) {
NSLog(@"An error occured: %@", connection.error);
}
}];
</pre>
<br />
An error occurs when the network is not available or when the server didn't respond in a timely fashion (timeout)<br />
<ul>
<li>Check the HTTP status code if no error occurred</li>
</ul>
<pre class="prettyprint"> [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
NSLog(@"Status Code: %d", connection.httpStatusCode);
}];
</pre>
<ul>
<li>Check the response header sent by the server</li>
</ul>
<pre class="prettyprint"> [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
NSLog(@"Response headers: %@", [((NSHTTPURLResponse*)connection.response) allHeaderFields]);
}];
</pre>
<ul>
<li>Check the received data</li>
</ul>
<pre class="prettyprint"> [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
NSLog(@"Received data length: %d Bytes", connection.data.length);
}];
</pre>
That's quite a few interesting things you can access from within the onFinished callback block.<br />
<br />
The image Data is automatically appended to the data property of the connection when a chunk is received. In this case, in the end, if the connection did not error, the image data is included in the connection.data. Let's get it, shall we?<br />
<br />
<pre class="prettyprint"> [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
if (connection.error) {
NSLog(@"Error: %@", connection.error);
return;
}
if ((connection.httpStatusCode < 200) || (connection.httpStatusCode >= 400)) {
NSLog(@"Oups: Status code: %d", connection.httpStatusCode);
return;
}
// Let's build an image with the received data
UIImage *image = [UIImage imageWithData:connection.data];
// Resize it? ...
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI with the image
});
}];
</pre>
<br />
One comment though. We assume the image to be fetched is a small sized image. If we were to fetch a big NASA picture of 300 MB, we would proceed differently. We would create a connection object, and then create a writeable stream in its onResponse callback, then in its onData callback we would append the downloaded chunks. This way the memory footprint of the download would be minimum.<br />
<br />
<h3>
Use the cache... Luke!</h3>
Ok so we can already download an image with the code above but let's go a bit further. What if we need to do some modifications to the image, or resize it? We would need to save it somewhere so that we don't need to resize it each time, so...<br />
<ul>
<li>We could save it to a file...</li>
<li>We could cache it !</li>
</ul>
<div>
Yes, let's use the builtin http cache! Yay!</div>
<div>
<br /></div>
<div>
The cache mechanism is handled by a super simple class in the Foundation framework which is named NSURLCache. You may ask yourself why I insist on caching the file. Well it's obviously to demonstrate an other cool feature of MCCURLConnection. </div>
<div>
<br /></div>
<div>
There is a callback method in NSURLConnectionDataDelegate protocol or so that allows one to say what needs to be cached when a request response needs to be cached. If the server is kind enough to not disable caching in it's returned headers then the NSURLConnection will trigger the delegate. And of course, now, MCCURLConnection has a block for this delegate method.<br />
How do we proceed ?<br />
<br />
Well, first we need to rewrite the code a bit so that we can set the onWillCacheResponse callback.<br />
<br /></div>
<pre class="prettyprint"> MCCURLConnection *connection = [[MCCURLConnection connectionWithRequest:request onFinished:^(MCCURLConnection *connection) {
if (connection.error) {
NSLog(@"Error: %@", connection.error);
return;
}
if ((connection.httpStatusCode < 200) || (connection.httpStatusCode >= 400)) {
NSLog(@"Oups: Status code: %d", connection.httpStatusCode);
return;
}
// Let's build an image with the received data
UIImage *image = [UIImage imageWithData:connection.data];
// Resize it? ...
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI with the image
});
}];
</pre>
<br />
Now, let's add the onWillCacheResponse callback. The basic idea in onWillCacheResponse is that it needs to return a NSCachedURLResponse that will be used to cache the request response. By default it returns the NSCachedURLResponse passed as parameter.<br />
<br />
<pre class="prettyprint"> extern UIImage *fitImageInSize(UIImage *, CGSize);
connection.onWillCacheResponse = ^NSCachedURLResponse *(NSCachedURLResponse *cachedResponse) {
UIImage *image = [UIImage imageWithData:cachedResponse.data];
CGFloat scale = [[UIScreen mainScreen]scale];
[connection.data setData:UIImageJPEGRepresentation(
fitImageInSize(image, (CGSize){80.0 * scale, 60.0 * scale}), 0.8f)];
NSCachedURLResponse *resizedResponse = [[NSCachedURLResponse alloc]initWithResponse:cachedResponse.response
data:connection.data];
return [resizedResponse autorelease];
};
</pre>
<br />
In this version, we resize and compress the image a bit (0.8), then we get back the jpg data of the image which we replace in the connection.data.<br />
<br />
By doing so, right after this block is run, the NSURLCache knows how to cache the request response with the jpg data AND the onFinished callback can now access the resized jpg data directly from the connection.data. So basically we did the two things in one shot. Wonderful!<br />
<br />
If we just run the app as it is, it will now be able to download the image, cache the resized jpg version in the shared NSURLCache and update the UI with the resized jpg image. If we rerun the app it will depending on the caching policy of the request, reload the image from the cache.<br />
To force the cache policy we set the request as follow:<br />
<br />
<pre class="prettyprint">NSURLRequest *request = [NSURLRequest requestWithURL:imageURL
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:60.0];
</pre>
<br />
<h3>
Full code</h3>
<div>
Here is the full code of the lab.<br />
<br /></div>
<pre class="prettyprint">#import "MCCURLConnection.h"
extern UIImage *fitImageInSize(UIImage *, CGSize);
- (void)viewWillAppear:(BOOL)animated {
CGFloat scale = [[UIScreen mainScreen]scale];
// Fetch the image
NSURLRequest *request = [NSURLRequest requestWithURL:imageURL
cachePolicy:NSURLRequestReturnCacheDataElseLoad
timeoutInterval:60.0];
MCCURLConnection *connection = [[MCCURLConnection connectionWithRequest:request
onFinished:^(MCCURLConnection *connection) {
if (connection.error || (connection.httpStatusCode < 200) || (connection.httpStatusCode >= 400)) {
NSLog(@"Error: %@ (status code: %d)", connection.error, connection.httpStatusCode);
return;
}
UIImage *image = [UIImage imageWithData:connection.data scale:scale];
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI with the image
});
}];
connection.onWillCacheResponse = ^NSCachedURLResponse *(NSCachedURLResponse *response) {
[connection.data setData:UIImageJPEGRepresentation(
fitImageInSize([UIImage imageWithData:response.data], (CGSize){80.0 * scale, 60.0 * scale}), 0.8f)];
return [[[NSCachedURLResponse alloc]initWithResponse:response.response
data:connection.data]autorelease];
};
}
</pre>
<h3>
Final word</h3>
<div>
As shown in this example, it doesn't take much to download a file from the internet using MCCURLConnection. In fact without the caching it's a matter of 3 lines of code. It is not much either to handle the caching of a resized image. With the caching we made, even with an offline network connection, the very same code will fetch the image from the cache, no need to change anything, it's magic :)<br />
<br />
You may find the MCCURLConnection class on my github account <a href="https://github.com/Orion98MC/MCCURLConnection" target="_blank">here</a>.</div>
<div>
<br /></div>
<div>
Cheers.</div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-30387126618588028052012-09-07T13:30:00.001+02:002012-09-22T12:20:04.849+02:00Objective-C blocks for fun (part 2)Last time I gave you a trick to run a block in a timer using a NSBlockOperation and I hope you enjoyed it ;)<br />
<br />
Today, I will show you how to avoid delegate method implementations using blocks.<br />
<br />
<a name='more'></a><br />
If you are like me, you love blocks because they let you tread code as data and thus allow you to use code here and there without the need to declare too much what your intent is to the compiler. They are great for callback for instance. Although blocks are just a step forward of function pointers, they really make sense in todays development where one can easily go from C to Ruby or Javascript the same day and write lambdas or anonymous functions and blocks almost for the same kind of problem resolution.<br />
<br />
But not all APIs are block aware. For example a lot of GUI classes in UIKit are still relying on the delegate paradigm although blocks would be a perfect fit for most of them. Hence, we create a lot of class wrappers ...<br />
<br />
<h3>
UIAlertView</h3>
Take for example the UIAlertView class. Most of the time you use it to either notify the user of something or to ask a Yes or No question like so:<br />
<br />
<pre>UIAlertView *av = [[[UIAlertView alloc]initWithTitle:@"Alert" message:@"This is an alert" delegate:nil cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ok", nil]autorelease];
[av show];
</pre>
<br />
But if you need the user's feedback you need to set the delegate to an object (often self) and implement one of the optional methods of the UIAlertViewDelegate protocol.<br />
<br />
I know, that's what we use to do before blocks, but now that we have blocks !?! Beuurk!<br />
<br />
There are two ways of solving this problem. Either we create a class wrapper or a subclass and set the delegate to that new class and implement the protocol in that class .... Or, we could use the runtime to inject the missing method directly in the object, make itself it's own delegate, and call a block from there. WhaOooOoOo that's a heavy duty... Let's do that!<br />
<br />
<h3>
Background</h3>
There is a great explanation of the trampoline concept by Mike Ash <a href="http://www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks-with-mutable-code.html" target="_blank">here</a>. Also, this solution is based of the comment of Keith Duncan, so thanks for the hint.<br />
<br />
We will use the Objective-C runtime to inject method implementations, although it seems to works on iOS 4+ and MacOS 10.6+ I cannot guaranty that the AppStore approval process will not reject this kind of code. It does no swizzling, so it may pass the validations, please let me know if it doesn't.<br />
<br />
<h3>
So...Trampoline</h3>
<div>
Injecting a method implementation can be done at run time using class_addMethod(). This function takes 4 arguments:</div>
<div>
<br /></div>
<pre>BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)</pre>
<div>
<ul>
<li>a Class object</li>
<li>a Selector</li>
<li>an Implementation (a pointer to a function with a special signature)</li>
<li>a type encodings string</li>
</ul>
</div>
<div>
Ok, so if we were to inject a method implementation we would need a function BUT we would like to use a block, not a function. See, blocks are more or less functions that embed context. So basically it's a structure that not only includes a function with the code but also includes some state management etc...</div>
<div>
<br /></div>
<div>
So we need a function... too bad we couldn't access the block function at least in a portable manner.</div>
<div>
<br /></div>
<div>
Enters the trampoline.</div>
<div>
<br /></div>
The basic idea of the trampoline is to send you back when you hit it. In our case the trampoline would be a function. This function would be the method implementation and it will bounce the block back to the caller :)<br />
<br />
Yay!<br />
<br />
Now how do we do that?<br />
<br />
<h3>
Creating a method</h3>
<div>
Let's write the implementation function first. In our case, the UIAlertViewDelegate method we would like to inject is:</div>
<div>
<br /></div>
<pre>- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex</pre>
<div>
<br /></div>
<div>
It's return type is void, so we need a trampoline function that returns void. It also takes 2 arguments, one is of UIAlertView* kind and the other is a NSInteger, so the function should also have these two arguments.</div>
<div>
<br /></div>
<div>
An implementation in Objective-C is a type IMP which is a pointer to a function that takes 2 mandatory arguments:</div>
<div>
<ul>
<li>id self</li>
<li>SEL _cmd</li>
</ul>
</div>
<div>
If the implementation requires more arguments they are put after the 2 mandatory arguments in the right order. So in our case the trampoline function signature should look like this:</div>
<div>
<br /></div>
<pre>void trampoline(id self, SEL _cmd, UIAlertView *alertView, NSUInteger buttonIndex);</pre>
<div>
<br /></div>
<div>
Now, inside this function we need to call a block. Yes, that's the whole point of the article remember? :)</div>
<div>
How can we do that? </div>
<div>
<br /></div>
<div>
Fortunately, the runtime is here to help. There is a way to associate a value to an object. The association is done with this function:</div>
<div>
<br /></div>
<pre>void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy)</pre>
<div>
<br /></div>
<div>
Now, depending of the policy we use, the documentation says that the value will be released when the object gets deallocated, which mean that if we use any policy except OBJC_ASSOCIATION_ASSIGN the object we provide will be released such that we don't need to hack the deallocation process. For our block to be persisted, we will force a heap copy with a policy of OBJC_ASSOCIATION_COPY_NONATOMIC (I think that if we restrain ourselves to the creation of blocks for UI objects delegation and thus stick on the main thread we can safely use the non atomic version, comments are welcome).</div>
<div>
<br /></div>
<div>
Next, we can get back the associated value whenever using: </div>
<div>
<br /></div>
<div>
id objc_getAssociatedObject(id object, void *key)</div>
<div>
<br /></div>
<div>
So, here is the overall process:</div>
<div>
<ol>
<li>create a method implementation trampoline function that execute a block associated with self</li>
<li>add the method to the UIAlertView instance</li>
<li>set the UIAlertView delegate to itself</li>
</ol>
</div>
<div>
Create the implementation trampoline:<br />
<br />
<br />
<pre>void trampoline(id self, SEL _cmd, UIAlertView *alertView, NSUInteger buttonIndex){
void(^block)(UIAlertView*, NSInteger) = objc_getAssociatedObject(self, _cmd);
if (block) block(alertView, buttonIndex);
}</pre>
</div>
<div>
<br /></div>
<div>
That's the bounce back trampoline. Now Let's add the method to the UIAlertView *av we created above:<br />
<br /></div>
<pre>void(^block)(UIAlertView*, NSInteger) = ^(UIAlertView*alertView, NSInteger buttonIndex) {
NSLog(@"Dismissed with button index: %d", buttonIndex);
};
objc_setAssociatedObject(av, @selector(alertView:didDismissWithButtonIndex:), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
class_addMethod([av class], @selector(alertView:didDismissWithButtonIndex:), (IMP)trampoline, "v@:@i");</pre>
<br />
Then, set the delegate:
<br />
<br />
<pre>av.delegate = av;</pre>
<br />
And show the alertView:
<br />
<br />
<pre>[av show];
</pre>
<br />
<h3>
Conclusion</h3>
<div>
Although, we managed to inject the method and use a block as delegate, it is unclear to me if we should be doing that. First, we need to be sure the AppStore approval process will not reject an App using this kind of code. Then it may no be as portable as a wrapper or a subclass.</div>
<div>
<br /></div>
<div>
However, if this solution could be proven usable for small delegations like in this example, it is worth to note that it allows you, for example, to create a UIAlertView macro that you can reuse anywhere in your projects.</div>
<div>
<br /></div>
<div>
All in all, this is a simple example, and I managed to make a more global solution for this matter using preprocessor macros to create the trampoline function and a simple class to add a method to any object. The code can be found <a href="https://github.com/Orion98MC/MCCBlockDelegate" target="_blank">here</a> on my github profile.</div>
<div>
<br /></div>
<div>
Cheers.</div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-67781751618168679232012-09-05T13:35:00.000+02:002012-09-22T12:20:34.351+02:00On ASIHTTPRequest replacement<br />
<div>
When it comes to making HTTP requests, the most used library historically was ASIHTTPRequest. But since it's development was abandoned by it's creator many developers are seeking for a good replacement.</div>
<br />
<a name='more'></a><br />
<br />
I have personally used ASIHTTPRequest for some time but always regretted that the library seemed over-bloated and tend to be annoyed by the obligation of adding many linked-against frameworks to my projects.<br />
<br />
As I was rewriting many of the conceptual objects I use in my applications to deliver them as Open Source material, I fell on the ASIHTTPRequest case once more. I had made a URL loader class but it was using ASIHHTPRequest and while reviewing the use case of the class I began to think it could be worth spending at most a day and see if I could come with a self-made self-content easy to use replacement for the ASIHTTPRequest calls.<br />
<br />
This post is the reviewed summary of this day.<br />
<br />
<br />
<br />
<div>
NEW! The class has been updated on github! You may checkout the new features and also check this blog post on the subject: <a href="http://orion98mc.blogspot.com/2012/09/seamless-downloads-with-mccurlconnection.html">http://orion98mc.blogspot.com/2012/09/seamless-downloads-with-mccurlconnection.html</a> </div>
<div>
</div>
<br />
<br />
<h3>
Spec</h3>
<div>
Before getting my hands in the programming phase I usually prefer to write the results I want to achieve. Most of the time this specifications phase consist of writing a sample code using the code I want to create. Something like:<br />
<br /></div>
<pre>/*
[MCCURLConnection connectionWithRequest:[NSURLRequest requestWithURL:aURL]
onResponse:^(NSURLResponse *r){ ... }
onData:^(NSData *chunk){ ... }
onFinished:^(NSError *e, NSInteger status){ ... }];
*/
</pre>
<div>
<br />
<br />
All in all, this doodling lead me to this kind of spec:<br />
<br />
- iOS 4+ (I don't support iOS 3.X anymore... Yay!)<br />
- Asynchronous (non blocking)<br />
- Block based. I tend to avoid delegation when possible.<br />
- Can manage concurrency<br />
- Can cancel requests<br />
- Very sparse API<br />
- Easy to use<br />
- Lightweight<br />
<div>
<br /></div>
<h3>
Perimeter</h3>
<div>
Since I want to be able to manage concurrency it seems straightforward to use NSOperationQueue for this. </div>
<div>
<br /></div>
<div>
I need to manage the loading of an URL so NSURLConnection with NSURLRequest seems a good investigation path. Also, NSURLConnection is asynchronous and handles cancelation.</div>
<div>
<br /></div>
<div>
Blocks imply iOS4+</div>
<div>
<br /></div>
<h3>
NSURLConnection</h3>
<div>
NSURLConnection is a sparse class that handles the loading of an URL with delegation. So to begin I created a NSObject subclass and added a NSURLConnection retained property to it such that I can set the delegate of NSURLConnection to the object itself. This way I can forward delegate callbacks to the callback blocks.</div>
<div>
<br /></div>
<h3>
NSRunLoop</h3>
<div>
NSURLConnection can operate in a custom RunLoop. By default it will schedule it's activity in the RunLoop of the main thread. The problem is that if you want to run the delegate blocks in a custom thread you have two choices:</div>
<div>
<br /></div>
<div>
* either create a new RunLoop and schedule the NSURLConnection object inside of it</div>
<div>
* or dispatch_async the delegate blocks from the delegate methods</div>
<div>
<br /></div>
<div>
I want to provide an object that can offer main-thread-free callbacks if the user requires it. I have so many times tried to stick any non GUI processing out of the main thread that this object deserves I take some time to figure out how to achieve this. So I will go for option 1, and schedule the NSURLConnection in a custom RunLoop.<br />
<br />
Thanks to UIKit, a custom RunLoop is automatically created in a new NSThread. So, if I submit a NSBlockOperation to a custom NSOperationQueue to create the connection, the queue will spawn (or dispatch to) a new Thread to execute the operation and thus, inside this executed block, a separate RunLoop will be running.</div>
<div>
<br /></div>
<div>
Example of code run inside the operation block to setup the NSURLConnection:<br />
<br /></div>
<div>
<pre>self.connection = [[[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:NO]autorelease];
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
</pre>
<br />
Notice the startImmediately:NO which allow me to schedule the connection in a custom RunLoop. The current RunLoop is the one of the thread we are in.<br />
<br />
One extra step is required to get the whole thing going. If I leave the connection like this, the thread will exit without having forward any delegate calls because nothing keeps the thread running.<br />
To keep the current thread running let's force the RunLoop to run in the NSDefaultRunLoopMode until the connection is finished or canceled:<br />
<br />
<pre>while (!(finished || canceled)) {
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
</pre>
<br />
<h3>
and they lived happily ever after</h3>
</div>
</div>
<div>
After few debugging and few refactoring the object is born.</div>
<div>
<br /></div>
<div>
It uses NSURLConnection and NSOperationQueue to fulfill the NSURLRequest. The full code is available <a href="https://github.com/Orion98MC/MCCURLConnection" target="_blank">here</a> on github.</div>
<div>
<br /></div>
<h3>
Example usage:</h3>
<div>
<h4>
GET www.google.com</h4>
</div>
<div>
<pre>NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.google.com]];</pre>
<pre>[MCCURLConnection connectionWithRequest:request
onResponse:^(NSURLResponse *response){ NSLog(@"Got response: %@", [(NSHTTPURLResponse *)response allHeaderFields]); }
onData:^(NSData *chunk){ NSLog(@"Got chunk: %@", [[[NSString alloc]initWithData:chunk encoding:NSUTF8StringEncoding]autorelease]); }
onFinished:^(NSError *error, NSInteger status){ NSLog(@"finished: %@ (status: %d)", error, status); }];
</pre>
<br />
<h4>
GET www.google.com on a separate thread</h4>
<pre>NSOperationQueue *queue = [[[NSOperationQueue alloc] init]autorelease];
queue.maxConcurrentOperationCount = 2;
MCCURLConnection *context = [MCCURLConnection contextWithQueue:queue onRequest:nil];
[context connectionWithRequest:request
onResponse:nil
onData:nil
onFinished:^(NSError *error, NSInteger status) { ... }];</pre>
<h4>
iOS, set the network activity indicator</h4>
</div>
<div>
<pre>static int count = 0;
[MCCURLConnection setOnRequest:^(BOOL started) {
if (started) count++;
else count--;
[[UIApplication sharedApplication]setNetworkActivityIndicatorVisible:count > 0];
}];</pre>
<h3>
Connection timeout and other settings...</h3>
</div>
<div>
MCCURLConnection is not magical! It doesn't set default behaviors under the hood. For example the connection timeout is set by UIKit, I think it's 60s for both OSX and iOS. You may change this behavior at NSURLRequest creation time.</div>
<div>
<br /></div>
<h3>
Conclusion</h3>
<div>
If you wish to replace ASIHTTPRequest with MCCURLConnection you will need to add some extra code since it does only the bare minimum. I personally prefer objects with limited actions but I understand that this is not the case for everyone especially if you need to setup a project very quickly.</div>
<div>
<br /></div>
<div>
Anyhow, it is easy to extend MCCURLConnection with additional constructors or wrappers by adding a category. The same applies for missing delegate callbacks.<br />
<br />
NEW! The class has been updated on github! You may checkout the new features and also check this blog post on the subject: <a href="http://orion98mc.blogspot.com/2012/09/seamless-downloads-with-mccurlconnection.html">http://orion98mc.blogspot.com/2012/09/seamless-downloads-with-mccurlconnection.html</a> </div>
<div>
<br /></div>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-62227286293570359392012-08-30T19:16:00.000+02:002013-01-05T11:38:39.145+01:00The Simplest Gallery UIScrollView class for iOS 4+ ... ever ;)In my last post about UIImage decompression nightmare, I told you I was working on a Gallery scrollView and now it's been released on <a href="https://github.com/Orion98MC/MCCGalleryViewDemo" target="_blank">github</a>.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeO9qPQzQnYk0pfldAoIJGR_uE5GL5KuFvkt_UcFwl37f7T8H2tFpMkDjbuh5JteRu2HcKbj0wGQc3SwUEgcPKSoswfPGjVGYEAq-H-1sxQgPU6K7-vIYv3mIIX-U08sxb0myjlEtmEPE/s1600/Simulateur_iOS-20120830-195014.jpg.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="168" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeO9qPQzQnYk0pfldAoIJGR_uE5GL5KuFvkt_UcFwl37f7T8H2tFpMkDjbuh5JteRu2HcKbj0wGQc3SwUEgcPKSoswfPGjVGYEAq-H-1sxQgPU6K7-vIYv3mIIX-U08sxb0myjlEtmEPE/s320/Simulateur_iOS-20120830-195014.jpg.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">the gallery in action on iPhone</td></tr>
</tbody></table>
<br />
<a name='more'></a><br />
<br />
This gallery allows you to display images or any kind of pages content in a scrollView. It also handles double taps and pinch-zooming of images.<br />
<br />
The demo project (code linked above) is highly commented and shows how in few lines of code, you can implement a gallery in your view controller.<br />
The demo also uses the UIImage background decompression concept I discussed before which allows it to display 1440 * 960 pixels images very quickly even on iPhones. If you run the demo on an iPad you will understand what I mean by very quickly.<br />
<br />
Do me a favor and give it a try. All feedback is welcome.<br />
<br />
Cheers.<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0tag:blogger.com,1999:blog-3249930764632385678.post-57608469112796830532012-08-29T13:03:00.001+02:002012-09-22T12:21:40.435+02:00On iOS UIImage decompression nightmareYesterday I tried to polish a Gallery class that I work on which I'll be posting to Github soon. This class is intended to be used as the ultimate gallery view ;) It's really easy to understand and thanks to blocks it is really easy to use. But anyways I will make a post when it's available on github.<br />
<br />
The problem I encountered while using my new gallery class to display images was that even though the pages creation was separated from the data sourcing using dispatch queues the first time an image was loaded, the scrolling would be really bad.<br />
<br />
<a name='more'></a><br /><br />
Here is the simplified culprit code:<br />
<br />
<pre class="prettyprint">dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%u.png", pageIndex]];
dispatch_async(dispatch_get_main_queue(), ^{
[((UIImageView*)page)setImage:image];
});
}
</pre>
<br />
<br />
I did a little bit of research on any known issue concerning -[UIImageView setImage:] being slow. And found some interesting posts like <a href="http://www.cocoanetics.com/2011/10/avoiding-image-decompression-sickness/" target="_blank">this one</a> where the author benchmarks the UIImage decompression for different image formats (png and jpg) on different iOS hardwares.<br />
<br />
The problem we have when we use the -[UIImageView setImage:] is that if the image was never decompressed, the framework (UIKit) will decompress it in a lazy manner, that is, when the image data really needs to be accessed and in our case it would be done in the block dispatched to the main queue.<br />
<br />
To improve our image sourcing block we would need to force the decompression of the image in the background queue and leave the main queue block as it is.<br />
<br />
Also, as the article pointed out, it is best for full screen images to use jpg format since the decompression of the image data is much quicker on all iOS platforms.<br />
<br />
Ok, so changing the images format is just a bit of mouse work... done.<br />
Now, how do we force the image to decompress it's data? Well there are many examples around on the web and I made my own by tearing parts of them.<br />
<br />
<pre class="prettyprint">NS_INLINE void forceImageDecompression(UIImage *image) {
CGImageRef imageRef = [image CGImage];
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef), 8, CGImageGetWidth(imageRef) * 4, colorSpace,kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);
CGColorSpaceRelease(colorSpace);
if (!context) { NSLog(@"Could not create context for image decompression"); return; }
CGContextDrawImage(context, (CGRect){{0.0f, 0.0f}, {CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)}}, imageRef);
CFRelease(context);
}
</pre>
Basically, this inlined function allows you to force the image data decompression by drawing the image in a bitmap context. This can be done in a background thread since iOS 4.0 IIRC.<br />
<br />
So now the overall sequence becomes:<br />
<br />
<pre class="prettyprint">dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"%u.jpg", pageIndex]];
forceImageDecompression(image);
dispatch_async(dispatch_get_main_queue(), ^{
[((UIImageView*)page)setImage:image];
});
}
</pre>
Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com5tag:blogger.com,1999:blog-3249930764632385678.post-13567679671819086152012-08-17T14:37:00.000+02:002013-01-05T11:28:16.381+01:00Objective-C blocks for funToday I had to solve a simple problem and since I am a lazy programmer I always tend to look for the solution that is the most easy to implement (less coding) but I never choose the easiest path to find this solution. I mean I try to follow this sentence: "Un objet est parfait quand on ne peut plus rien lui retirer de futile" which could more or less be translated to "An object is perfect when no more can be taken away". I don't know who ever said that but I often remind me this sentence when I work.<br />
<br />
<h3>
Problem:</h3>
I want to register a timer (NSTimer) that runs a block.<br />
<br />
<a name='more'></a><br />
<h3>
Solution:</h3>
<pre class="prettyprint">NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.7
target:[NSBlockOperation blockOperationWithBlock:^{ /* do this! */ }]
selector:@selector(main)
userInfo:nil
repeats:NO
];
</pre>
<br />
The NSBlockOperation instance is retained by the timer.<br />
The -[NSBlockOperation main] will run the block.<br />
<br />
Enjoy :)<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com3tag:blogger.com,1999:blog-3249930764632385678.post-80189255050333722412012-08-12T18:19:00.000+02:002013-03-01T17:07:36.404+01:00Two hours I'll never get backToday I had to install node.js on a CentOS 5.7 box.<br />
As usual with system administration you never know how long it will take to complete. But since I managed to do it and found it rather painful I wanted to share the moment with you :)<br />
This is a commented copy/past of the operation log.
<br />
<br />
<a name='more'></a><br />
<br />
<pre>$ ssh orion@xxxxx
orion@xxxxx password:
Last login: Tue Jul 10 12:01:23 2012 from xxxxx
CentOS release 5.7 (Final)
Linux xxxxx.ovh.net 2.6.34-xxxx-std-ipv4-32 #2 SMP Thu Jun 17 07:12:38 UTC 2010 i686 i686 i386 GNU/Linux
</pre>
This server is hosting many web sites and I really don't want to mess the things up so I'm going to be extra-careful and keep all my activity in a sandbox.<br />
<br />
When I am on a production server I usually create a "inst" folder in my $HOME directory where I put all the sources I need to compile.
<br />
<br />
<pre>$ cd inst
</pre>
Then get the sources. At this point I really don't bother with potential dependencies since I know the problem will come soon enougth... IYKWIM.
<br />
<br />
<pre>$ sudo wget http://nodejs.org/dist/v0.8.6/node-v0.8.6.tar.gz
--2012-08-12 15:44:07-- http://nodejs.org/dist/v0.8.6/node-v0.8.6.tar.gz
Resolving nodejs.org... 8.12.44.238
Connecting to nodejs.org|8.12.44.238|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11468801 (11M) [application/octet-stream]
Saving to: `node-v0.8.6.tar.gz'
100%[======================================>] 11,468,801 3.50M/s in 3.1s
2012-08-12 15:44:11 (3.50 MB/s) - `node-v0.8.6.tar.gz' saved [11468801/11468801]
$ tar zxvf node-v0.8.6.tar.gz
</pre>
<br />
Ok, now, ... let's meet the problems
<br />
<br />
<pre>$ ./configure
File "./configure", line 325
o['default_configuration'] = 'Debug' if options.debug else 'Release'
^
SyntaxError: invalid syntax
</pre>
<br />
I told you...<br />
A bit of search in g**gle tells me the problem must come from an outdated python package bundled with the CentOS 5.7. mmmmm... am I gonna like this distro or not...
<br />
<br />
<pre>$ python --version
Unknown option: --
usage: python [option] ... [-c cmd | -m mod | file | -] [arg] ...
Try `python -h' for more information.
</pre>
<br />
Outdated it seems indeed. Okay I've never used Python. It doesn't comply well with the GNU command line long options though :)
<br />
<br />
<pre>$ python -V
Python 2.4.3
</pre>
<br />
Many comments on the web say that python < 2.6 cannot build node.js sources so I need a newer python.
Latest stable is (at the time I am writing these lines) 2.7.3.
<br />
<br />
<pre>$ sudo wget http://www.python.org/ftp/python/2.7.3/Python-2.7.3.tgz
$ tar zxvf Python-2.7.3.tgz
</pre>
I will install all of the binaries in a safe place and will prefix every configure. Since the /var/www is mount of a disk with a lot of free space. I made a folder named mcc inside of it for all my stuff.
<br />
<br />
<pre>$ ./configure --prefix /var/www/mcc/
...
configure: creating ./config.status
config.status: creating Makefile.pre
config.status: creating Modules/Setup.config
config.status: creating Misc/python.pc
config.status: creating Modules/ld_so_aix
config.status: creating pyconfig.h
config.status: pyconfig.h is unchanged
creating Modules/Setup
creating Modules/Setup.local
creating Makefile
$ make
</pre>
<br />
At this point you would believe just like me that it's going to be perfect. How naive we are.
make did finish without any error. which is great.<br />
<br />
There seems to be a consensus in the community of people installing python from sources on linux distros that "make altinstall" is safer (especially if you prefixed your configure). I take it.
<br />
<br />
<pre>$ sudo make altinstall
$ /var/www/mcc/bin/python2.7 -V
Python 2.7.3
</pre>
<br />
Now Python 2.7.3 is installed in /var/www/mcc/bin. Thrilled!
Let's go on with node.js not without having put the new python path in the $PATH environment variable and symlink python.
<br />
<br />
<pre>$ pushd /var/www/mcc/bin
$ sudo ln -s python2.7 python
$ export PATH=/var/www/mcc/bin:$PATH
$ popd
</pre>
<br />
Same player, try again.
<br />
<br />
<pre>$ ./configure --prefix /var/www/mcc/
{ 'target_defaults': { 'cflags': [],
'default_configuration': 'Release',
'defines': [],
'include_dirs': [],
'libraries': []},
'variables': { 'host_arch': 'ia32',
'node_install_npm': 'true',
'node_install_waf': 'true',
'node_prefix': '/var/www/mcc/',
'node_shared_openssl': 'false',
'node_shared_v8': 'false',
'node_shared_zlib': 'false',
'node_use_dtrace': 'false',
'node_use_etw': 'false',
'node_use_openssl': 'true',
'target_arch': 'ia32',
'v8_no_strict_aliasing': 1,
'v8_use_snapshot': 'true'}}
creating ./config.gypi
creating ./config.mk
</pre>
<br />
Yesss. but then...
<br />
<pre>$ make
...
Traceback (most recent call last):
File "../../tools/js2c.py", line 36, in <module>
import bz2
ImportError: No module named bz2
make[1]: *** [/home/orion/inst/node-v0.8.6/out/Release/obj/gen/libraries.cc] Error 1
make[1]: Leaving directory `/home/orion/inst/node-v0.8.6/out'
make: *** [node] Error 2
</module></pre>
<br />
Ishhhk!
It misses the bz2 support in python... I hate snakes. Bzzzzz!<br />
To be fair, if I had read the whole Python build log (around line #21245675554) I would have known that it didn't build the bz2 support.<br />
Okay so to have the bz2 support it must have detected the bz2 library or something. Let's check that with yum:
<br />
<br />
<pre>$ yum list | grep bz
bzip2.i386 1.0.3-6.el5_5 installed
bzip2-libs.i386 1.0.3-6.el5_5 installed
bzip2-devel.i386 1.0.3-6.el5_5 base
</pre>
<br />
Then, get it:
<br />
<br />
<pre>$ sudo yum install bzip2-devel
...
Complete!
</pre>
<br />
And now you may be saying that I did touch the system and installed bzip2-devel system wide. You are right but it's a standard package for CentOS not a custom made from a custom repository.
And here we go again, let's rebuild python once more.
<br />
<pre>$ ./configure --prefix /var/www/mcc/ && make clean && make
$ sudo make altinstall
</pre>
<br />
To check that python has bz2 support:
<br />
<pre>$ python -c "import bz2; print bz2.__doc__"
The python bz2 module provides a comprehensive interface for
the bz2 compression library. It implements a complete file
interface, one shot (de)compression functions, and types for
sequential (de)compression.
</pre>
<br />
Okay, now let's build node ... again.
<br />
<pre>$ cd ../node-v0.8.6
$ make
</pre>
<br />
And Yes, It built BUT...
<br />
<pre>$ sudo make install
make -C out BUILDTYPE=Release V=1
make[1]: Entering directory `/home/orion/inst/node-v0.8.6/out'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/orion/inst/node-v0.8.6/out'
ln -fs out/Release/node node
python tools/install.py install
File "tools/install.py", line 219
cmd = args[1] if len(args) > 1 else 'install'
^
SyntaxError: invalid syntax
make: *** [install] Error 1
</pre>
<br />
F*CK!
<br />
<br />
<pre>$ python -V
Python 2.7.3
</pre>
<br />
....(12 seconds of thinking)...
<br />
<br />
<pre>$ sudo python tools/install.py install
installing /var/www/mcc/include/node/ares.h
installing /var/www/mcc/include/node/ares_version.h
installing /var/www/mcc/include/node/uv.h
...
installing /var/www/mcc/lib/node_modules/npm/node_modules/which/bin/which
symlinking ../lib/node_modules/npm/bin/npm-cli.js -> /var/www/mcc/bin/npm
updating shebang of /var/www/mcc/bin/npm to /var/www/mcc/bin/node
</pre>
<br />
Houra! It worked. Although I don't understand why make install failed at once. Maybe a hard coded python path or an exported PATH env variable in the makefile did override my setup. I should report this to the developers.
Now let's enjoy this with a great node.js program:
<br />
<br />
<pre>$ /var/www/mcc/bin/node -e 'console.log("That all folks!")'</pre>
<br />
EDIT:<br />
Concerning the "sudo python tools/install.py" trick. The thing here is that root may not have the right (newly updated) python path because I did not change anything in /etc/profile, right? What is a bit confusing here is that I did install the whole bunch of new tools' versions in a private directory (/var/www/mcc). And logically I should own this directory and thus not use any "sudo" to install stuff in it. Lesson learned ... ;)<br />
<br />
Oh and also, don't forget to set your $NODE_PATH to the right node_modules directory path. In my case I have set it to /var/www/mcc/lib/node_modules<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com13tag:blogger.com,1999:blog-3249930764632385678.post-66753317767464096572012-07-25T12:59:00.001+02:002013-01-05T11:40:38.764+01:00On javascript asynchronous callbacksOne of the true beauty of javascript, in my opinion, is the <b>callback</b> we use in asynchronous calls.
<br />
Most of the time callbacks are anonymous functions passed as the last parameter to an asynchronous function. We use a lot of callbacks in node.js environment.
<br />
However, sometimes it can become a bit confusing when many asynchronous functions need to be called. In this post I'll focus on parallel asynchronous function calls and overall completion callback.<br />
<br />
<a name='more'></a><br />
<br />
While writing an RRD update script, I needed to get the value of a set of data sources that can be dynamically specified by the caller. The data sources values are extracted from a Mongodb database. Before doing the RRD update call, I needed to collect the data sources values asynchronously. The process was something like this:<br />
<br />
<pre class="prettyprint">function collectValues (data_sources, when_done_callback) {
/* Collect values */
data_sources.forEach(function(ds) {
/* asynchronous mongodb call for each ds */
}
}
</pre>
The problem is how to do the asynchronous database calls and then when they all complete, execute the <b>when_done_callback</b> ?<br />
I'm sure everyone has his own way of solving this problem but, here is mine:<br />
<br />
<pre class="prettyprint linenums">function whenDone(doneCallback) {
var left = 0
, done = function() { if (--left === 0) { doneCallback(); } };
return function doThis(work, n) {
if (typeof n !== 'undefined') left += n;
else left++;
process.nextTick(function(){ work(done); });
};
}
</pre>
So, how do I use this function in the context of previous example?
<br />
<pre class="prettyprint">function collectValues (data_sources, when_done_callback) {
var after = whenDone(when_done_callback);
/* Collect values */
data_sources.forEach(function(ds_name) {
after(function(done) {
collection.count(/* query for this ds */, function (error, count) {
/* Do something with the error and count */
done(); /* It is important to call the done function */
});
});
}
}
</pre>
<br />
<h3>
What it does</h3>
<div>
The function takes an unique <b>doneCallback</b> parameter and returns a function that has 3 variables set in it's context. </div>
<div>
<ul>
<li>A counter (<b>left</b>) that will record how many asynchronous functions must complete before calling the doneCallback</li>
<li>A <b>done</b>() function that is bound to the same context (i.e it can access the <b>left</b> counter). Calling this function will decrease the <b>left</b> counter and if the counter is 0 call the <b>doneCallback</b></li>
<li>The <b>doneCallback</b></li>
</ul>
<div>
When you first call the whenDone() function you bind the doneCallback and get a new <b>doThis</b> function that you can use to execute asynchronous functions. At this point the counter is still 0.</div>
</div>
<div>
<br /></div>
<div>
When you use the <b>doThis</b> function you pass it an anonymous function as argument. Using the doThis function automatically increases the counter by one (you can however specify by how much it should increase as second argument). </div>
<div>
All your asynchronous work is done in this anonymous function. The anonymous function gets as unique argument the <b>done</b> function that you need to run to decrease the counter.</div>
<div>
<br /></div>
For best results we need to call the <b>doThis</b> function in the same tick. Else it could happen that the <b>doneCallback</b> would run multiple times.<br />
<br />
<br />Thierry Passeronhttp://www.blogger.com/profile/17455367472399877121noreply@blogger.com0