The dawn of the web introduced us to URLs starting with "http://www". For those old enough to remember those days of Lynx, Mosaic, and Netscape, "www" was true to its meaning of "world-wide web". Suddenly anyone connected to the Internet was able to reach out to any remote place in the world, also connected to the net, and browse the information published there. Powerful.
Since then a lot has changed. The devices we use to access the net had moved from our desks to our palms, and soon to our glasses, and with the mobility they afford, the Internet access got a new dimension - that of context, or location. So in addition to what's out there (www) now what's over here becomes an interesting question. Perhaps some new URLs, like "http://here" and "http://now", start to make sense. Seems that I'm not the only one thinking so. Nokia appears to be doing something like that with http://here.com. If face recognition becomes a feature of Google Glass, then a "http://you" makes sense too. I'm probably stating the obvious here, but what I'd like to see is more of these 2 things:
1. The ability of users to freely add and annotate the content presented. Think of "Augmented Reality Wikipedia". Like "digital graffiti" curated through a vote-based meritocracy, or by applying a filtering based on what your contacts on social networks think of that content.
2. More mash-ups. With the growing number of web services (over 9000 APIs as of now), and the continued move toward a more semantic web, the ability to mash things up should continue to grow.
It'd be interesting to see how all this will unfold, and maybe even contribute to this vision. Such projects, once they pass a critical mass of adoption, they tend to snowball fast.
Tuesday, May 14, 2013
Friday, May 10, 2013
Rendering office documents in HTML - an idea whose time has come
A while ago I was working on a project that needed rendering PDFs on iOS. There are several ways to do that. On iOS, that is. My client wanted a solution for Android too, and was complaining about the lack of similar capabilities there. Since Android wasn't one of my areas of competence at the time I wasn't involved with that effort directly. However I kept hearing about the need to use some 3rd party, rather expensive, libraries.
So naturally it dawned on me this idea: why don't the "owners" of the PDF format, Adobe, provide a cross-platform viewer. The natural solution would be an HTML based approach, since virtually all popular platforms provide a way to display HTML. At the time I was thinking that the capabilities provided by HTML 5 and CSS 3 should be enough to accomplish the "print-quality" level of rendering offered by Adobe's Acrobat Reader or Apple's Preview. Since Adobe wasn't doing much about it, it seemed a pretty good opportunity. Turns out that wasn't such a bad idea. In fact folks at Crocodoc were banging at it since 2006. Today was the payback. Good for them.
I only heard about them today. A brief glance at their API shows that right now it fetches the documents from some servers, where they're processed and converted from PDF to HTML. With this dependency on a server-side component it doesn't seem to have support for offline viewing. I guess one could hack around and save the generated HTML and all the referenced components (images, CSS, and what not), but that may be a brittle solution. With their new owner I'm sure they'll keep improving their technology and this may well become a compelling cross-platform document rendering solution.
So naturally it dawned on me this idea: why don't the "owners" of the PDF format, Adobe, provide a cross-platform viewer. The natural solution would be an HTML based approach, since virtually all popular platforms provide a way to display HTML. At the time I was thinking that the capabilities provided by HTML 5 and CSS 3 should be enough to accomplish the "print-quality" level of rendering offered by Adobe's Acrobat Reader or Apple's Preview. Since Adobe wasn't doing much about it, it seemed a pretty good opportunity. Turns out that wasn't such a bad idea. In fact folks at Crocodoc were banging at it since 2006. Today was the payback. Good for them.
I only heard about them today. A brief glance at their API shows that right now it fetches the documents from some servers, where they're processed and converted from PDF to HTML. With this dependency on a server-side component it doesn't seem to have support for offline viewing. I guess one could hack around and save the generated HTML and all the referenced components (images, CSS, and what not), but that may be a brittle solution. With their new owner I'm sure they'll keep improving their technology and this may well become a compelling cross-platform document rendering solution.
Labels:
Adobe
Saturday, May 04, 2013
Caveats of using MPMoviePlayerController
For a recent iOS project I had to play some videos, embedded in a subview of a larger view. One way to achieve that is to employ the MPMoviePlayerController. At first glance that component seems easy enough to use. Folks at Apple are trying to help by providing the following code snippet, right there in the official docs:
Right on. I'm adding this stuff to my app, and ... nothing happens. Nothing plays, just a black rectangle where the video player was supposed to show up. My first reaction was to look if they have a complete sample project that I could play with, and learn how to use the API. They do. I open it and it's using manual memory management (pre-ARC). Yuck ! Still I look there and see that they're using notifications to observe the state of the player. That sounds like a good way to debug what's going on. I do the same in my code. None of the notifications get called. What the ... ?
On a 2nd look at the code above, it becomes clear that in an ARC project, like mine was, the player local variable will be gone at the end of its enclosing scope. No wonder that nothing happens. The player must be kept alive through a strong ivar, or property. Doing that fixed my problem. So Apple's code snippet is pretty bad. It would have worked in the pre-ARC projects, albeit by leaking memory, but obviously this stuff was never updated for ARC.
Luckily I have plenty of experience doing manual memory management, and I can handle old code bases, like so many of Apple's code samples are. For now I'll inform their docs team of the problem.
MPMoviePlayerController *player =
[[MPMoviePlayerController alloc] initWithContentURL: myURL];
[player prepareToPlay];
[player.view setFrame: myView.bounds]; // player's frame must match parent's
[myView addSubview: player.view];
// ...
[player play];
Right on. I'm adding this stuff to my app, and ... nothing happens. Nothing plays, just a black rectangle where the video player was supposed to show up. My first reaction was to look if they have a complete sample project that I could play with, and learn how to use the API. They do. I open it and it's using manual memory management (pre-ARC). Yuck ! Still I look there and see that they're using notifications to observe the state of the player. That sounds like a good way to debug what's going on. I do the same in my code. None of the notifications get called. What the ... ?
On a 2nd look at the code above, it becomes clear that in an ARC project, like mine was, the player local variable will be gone at the end of its enclosing scope. No wonder that nothing happens. The player must be kept alive through a strong ivar, or property. Doing that fixed my problem. So Apple's code snippet is pretty bad. It would have worked in the pre-ARC projects, albeit by leaking memory, but obviously this stuff was never updated for ARC.
Luckily I have plenty of experience doing manual memory management, and I can handle old code bases, like so many of Apple's code samples are. For now I'll inform their docs team of the problem.
Saturday, April 27, 2013
Keeping the code clean of warnings helps your productivity
In some Fortune 500 companies I worked we had an official policy of 0 compilation warnings allowed in the code. That was a good practice that saved us of many troubles. Since then I try to follow that practice in my projects.
Let's see an example:
If I placed this code in a project with the default settings created by Xcode, the result wouldn't output the "OK" string, due to the "case1:" typo which transformed the "case 1:" case statement into an unused label. The compilation wouldn't produce any warning. Neither would the static analyzer.
You can however catch such problems at compile time, by changing the default settings like so:
This enables all warnings. The following setting treats all warning as errors:
If I now try to compile I get this error:
Catching this bug at compile time is much better than later when the app may have been released.
Another useful setting to have is this:
which runs the static analyzer on every compilation. I found this combination of settings very useful to smoke out bugs shortly after they have been introduced.
Let's see an example:
NSLog(@"Hello, World!");
int i = 1;
switch (i) {
case1:
NSLog(@"OK");
break;
}
If I placed this code in a project with the default settings created by Xcode, the result wouldn't output the "OK" string, due to the "case1:" typo which transformed the "case 1:" case statement into an unused label. The compilation wouldn't produce any warning. Neither would the static analyzer.
You can however catch such problems at compile time, by changing the default settings like so:
Another useful setting to have is this:
which runs the static analyzer on every compilation. I found this combination of settings very useful to smoke out bugs shortly after they have been introduced.
Labels:
Objective-C,
Xcode
Saturday, April 20, 2013
Unexpected side effect of fast enumeration in Objective-C
Fast enumeration is a relatively new capability in Objective-C. For a thorough survey of all the ways one can enumerate through a collection, you can see this post.
In a recent project I had a code sequence like this (modified here for illustration):
My expectation was that at the end of the for loop the number variable would hold the last value of the array. Here's what I get instead:
Strangely the value comes back as nil. Which is what it was initialized to before entering the loop. Could that be the case ? Let's try this instead:
which produces:
Nope, I still get nil, not the @100 value at the entry of the loop. So it seems that fast enumeration blocks reset the value of the iteration pointer in the outer context back to nil. This is, at least to me, unexpected. Maybe it's a bug. I'll see what Apple has to say.
In a recent project I had a code sequence like this (modified here for illustration):
NSArray *array = @[@1, @2];
NSNumber *number = nil;
for (number in array) {
NSLog(@"number: %@", number);
}
NSLog(@"Last number: %@", number);
My expectation was that at the end of the for loop the number variable would hold the last value of the array. Here's what I get instead:
2013-04-19 17:13:06.223 FastEnumBug[49016:303] number: 1
2013-04-19 17:13:06.240 FastEnumBug[49016:303] number: 2
2013-04-19 17:13:06.241 FastEnumBug[49016:303] Last number: (null)
Strangely the value comes back as nil. Which is what it was initialized to before entering the loop. Could that be the case ? Let's try this instead:
NSArray *array = @[@1, @2];
NSNumber *number = @100;
for (number in array) {
NSLog(@"number: %@", number);
}
NSLog(@"Last number: %@", number);
which produces:
2013-04-20 18:47:34.209 FastEnumBug[62468:303] number: 1
2013-04-20 18:47:34.212 FastEnumBug[62468:303] number: 2
2013-04-20 18:47:34.212 FastEnumBug[62468:303] Last number: (null)
Nope, I still get nil, not the @100 value at the entry of the loop. So it seems that fast enumeration blocks reset the value of the iteration pointer in the outer context back to nil. This is, at least to me, unexpected. Maybe it's a bug. I'll see what Apple has to say.
Labels:
Apple,
Objective-C
Saturday, March 23, 2013
Charging for wireless services by auction
I've been thinking about this for a while now. All mobile network operators have a rigid price structure, in some markets, like Canada, with outrageous costs. Yet when certain areas of the network are idle, due to low traffic, the network equipment remains unused, and is producing no revenue. It strikes me as a very inefficient way to allocate and manage resources. I believe an auction-based model, where available capacity is up for bidding would be more efficient.
Once the costs of laying out a network have been sunk, the ongoing cost of operations should dwarf the initial investment, and should allow for a wide range of pricing to make economic sense. That is, the cost of allowing access to a spare channel of communication between a mobile device and the network shouldn't be much higher than the cost of keeping that channel unused, on stand-by. I'd venture to guess that most of the additional cost is for the energy used to power the transmission.
Hence the opportunity, if I'm a customer in the right place at the right time, and the cell covering that location has plenty of spare capacity at that particular time, I should be given the opportunity to get access to the network at a rate lower than the going rate. Whereas I would almost never pay the $10/GB going rate, I would be willing to pay a lower price. Because of the rigid pricing, however, this opportunity goes wasted. I don't get to use the service, the service provider doesn't get paid. Lose-lose scenario. Flexible pricing would turn it in a win-win.
Conversely, sometimes you might find yourself in an area that's highly congested, with no physical ability to accommodate everyone, even at the going rate. Some calls will need to be dropped. Flexible pricing would be a way to guarantee a connection for the higher bidders. So sometime I would be willing to pay above the $10/GB rate.
Such flexibility would benefit all parties. Sure there would be some complexity added to metering and billing, and some signalling mechanisms should be devised for dealing with the bidding process, but the gains may far outweigh the costs. Why nobody implemented something like this, especially for pre-paid or pay-per-use plans, remains a mystery.
Once the costs of laying out a network have been sunk, the ongoing cost of operations should dwarf the initial investment, and should allow for a wide range of pricing to make economic sense. That is, the cost of allowing access to a spare channel of communication between a mobile device and the network shouldn't be much higher than the cost of keeping that channel unused, on stand-by. I'd venture to guess that most of the additional cost is for the energy used to power the transmission.
Hence the opportunity, if I'm a customer in the right place at the right time, and the cell covering that location has plenty of spare capacity at that particular time, I should be given the opportunity to get access to the network at a rate lower than the going rate. Whereas I would almost never pay the $10/GB going rate, I would be willing to pay a lower price. Because of the rigid pricing, however, this opportunity goes wasted. I don't get to use the service, the service provider doesn't get paid. Lose-lose scenario. Flexible pricing would turn it in a win-win.
Conversely, sometimes you might find yourself in an area that's highly congested, with no physical ability to accommodate everyone, even at the going rate. Some calls will need to be dropped. Flexible pricing would be a way to guarantee a connection for the higher bidders. So sometime I would be willing to pay above the $10/GB rate.
Such flexibility would benefit all parties. Sure there would be some complexity added to metering and billing, and some signalling mechanisms should be devised for dealing with the bidding process, but the gains may far outweigh the costs. Why nobody implemented something like this, especially for pre-paid or pay-per-use plans, remains a mystery.
Labels:
mobile
Saturday, February 16, 2013
UIView gotchas in iOS
In iOS the UI consists of a hierarchy of views and view controllers, linked through containment relationships. That's following the common composite design pattern, which should be familiar to most programmers. In addition there is a specific system-imposed lifecycle, which governs how all those pieces come into existence, and various callbacks that the system (Cocoa Touch) calls at specific points in this lifecycle. All this is fairly well documented, but with experience comes additional insights, and lessons learned the hard way. Here's what I discovered:
If your code relies on the coordinates of a view's frame, then your best bet is reading the frame in:
You may be tempted to use - (void)viewDidLoad for the same purpose, which gets called earlier in the lifecycle, however at that time the frame may not have its value set accurately. I find this happening often especially for iPad. Most times I use the storyboard (and IB in the past) to implement my UIs. I usually lay it out in portrait mode only, and rely on the autoresizing mask, or layout constraints, to position everything properly. Because on iPad you can launch an app in landscape mode directly, the frame in viewDidLoad will appear as defined in the storyboard, with the size for portrait. If those values are relied upon later, that would result in problems.
This problem may also occur in obscure contexts, where one is not directly using the frame. For example in a previous post I was mentioning some weird behaviour when setting the value of a progress bar, like so:
[self.progressBar setProgress:0.5 animated:YES];
Apple took a look at it and informed me that "The view animates from an undefined state. Doing such things in the viewDidLoad can only lead to problems.".
If your code relies on the coordinates of a view's frame, then your best bet is reading the frame in:
- (void)viewWillAppear:(BOOL)animated
You may be tempted to use - (void)viewDidLoad for the same purpose, which gets called earlier in the lifecycle, however at that time the frame may not have its value set accurately. I find this happening often especially for iPad. Most times I use the storyboard (and IB in the past) to implement my UIs. I usually lay it out in portrait mode only, and rely on the autoresizing mask, or layout constraints, to position everything properly. Because on iPad you can launch an app in landscape mode directly, the frame in viewDidLoad will appear as defined in the storyboard, with the size for portrait. If those values are relied upon later, that would result in problems.
This problem may also occur in obscure contexts, where one is not directly using the frame. For example in a previous post I was mentioning some weird behaviour when setting the value of a progress bar, like so:
[self.progressBar setProgress:0.5 animated:YES];
Apple took a look at it and informed me that "The view animates from an undefined state. Doing such things in the viewDidLoad can only lead to problems.".
Subscribe to:
Posts (Atom)



