One of my pet hates is purchasing DVDs and Blu-Rays. It seems so clunky and out-dated in an age where nearly everything I consume is stored on my hard drives. I also have a real problem with paying for a physical product and then having to wait an average of 70 seconds to start playing the movie due to sitting through either adverts bundled on the disc or anti-piracy messages that can’t be skipped (or elaborate menus that take 20 seconds of animation before you can select “play film”).
The only time I ever buy them these days is when there is a film I really loved and has extras that I want to watch. Most recently, this has been The LEGO Movie and The Grand Budapest Hotel.
Today I was able to cancel my pre-orders of both from Amazon thanks to iTunes Extras now being re-enabled on the Apple TV. iTunes Extras are essentially small HTML5 apps bundled with movies you buy from iTunes and act as the “extras” piece you usually get with a DVD or Blu-Ray. Until recently, they’ve only worked on Mac (and for a while on the original Apple TV) so I haven’t really spent much time with them - I don’t watch films on my computer.
I’ve only had a quick play with them but I’m liking what I see already. Both films were cheaper on iTunes (HD) than buying on a physical disc and came with the same extras as far as I can tell. In addition, The LEGO Movie was available today whereas the Blu-Ray isn’t available for another 2 weeks here in the UK. Best of all, when you start the film, it starts immediately with no anti-piracy notices and nothing that can’t be fast-forwarded; you get exactly what you paid for.
So how does it work? Simply press “play” on a movie with iTunes Extras and you’ll be shown a splash screen where you can then choose to watch the movie as usual, view the extras that are available, view a cast list (along with other films they are featured in), or view similar films. One strange thing I found was that the extras for The LEGO Movie didn’t show up on the Apple TV and looking at the listing within iTunes it says “Available on your Mac or PC”. The movie is featured prominently in the marketing material for the new extras so I have to imagine that it just hasn’t rolled out fully yet.
For those that don’t have an Apple TV yet, this is another feature which might persuade them. However, I’m still anticipating an updated model later in the year with some form of game support; the combination of an A8 chip, the new Metal framework, and the controllers introduced with iOS 7 seems to point to what could be a very nice, if simple, gaming machine.
To get iTunes Extras, simply apply the update that has appeared on Apple TV today. Lots of films have iTunes Extras with them and many previous films have had extras added which you get automatically if you already own the film. iTunes Extras are also coming to iOS 8 when it launches later this year.
The previous behaviour for iPads was that they would run a 320x480px boxed version of your app in the center of the display. If you pressed the 2x button, the app would be enlarged to 640x960px but would still use the same assets leading to a fuzzy mess. The retina iPads had it slightly better as they would use the larger assets and retina font smoothing leading to a better experience. In iOS 7, retina iPads (currently the 3rd and 4th generation) still allow this same toggle but the non-retina iPads (only the iPad 2 and iPad Mini on iOS 7) are now locked at 2x using your retina assets and font smoothing.
This is fantastic news as it signals the end of non-retina device support. If you are making an iPhone app that is iOS 7 only (sensible if it’s a new app), you no longer have to worry about supporting non-retina devices as the iPads will use your retina assets. For developers, this has 3 key benefits:
You only need @2x files in your app bundle: This leads to smaller sizes for your app bundle and less hassle in creating all of your 1x assets in the first place.
Less complex code for images fetched over network as you only need one size: For example, in WallaBee I have a UIImageView subclass that fetches images for me based on the scale of the UIScreen. If the UIImageView is 100 points square, it would download a 200x200px image on retina devices and 100x100px image on non-retina devices. This is no longer necessary saving some complexity.
You can use finer design elements: for example, using 1px (rather than 1pt) dividing lines. You can also use images that have an odd number of pixels (previously a 99px image was generally forbidden as you’d need a 49.5px image for non-retina displays which wouldn’t work). Nearly every designer I’ve worked with has designed at retina resolution with odd numbered sizes for key elements so this is very welcome!
I’m really excited that we can now drop support for non-retina displays; it’ll definitely speed up some of my workflows. You will obviously still need to support non-retina devices if you are building a Universal or iPad only app though.
I’ve been rewatching Frasier recently (just finished the 7th season) and it is still an absolutely fantastic show. Witty writing, great characters, and very few bad episodes (rare in most comedy series - there are usually a lot of duds as they age).
In any case, one of the episodes I’ve just watched, They’re Playing Our Song, has Frasier composing his own theme tune for his radio show. Rather than being a 10 second jingle, it turns into a 2-minute orchestral track with a voiceover from Niles.
I finally fulfilled one of my longterm dreams and bought the LEGO Super Star Destroyer whilst it was on offer for Star Wars Day (May 4th). The Super Star Destroyer (also known as ‘The Executor’) is a complete beast; it measures in at around 4.2 feet long and 8 pounds in weight. It’s the most expensive set LEGO currently sell but is 3rd in terms of number of pieces (it has 3152 pieces compared to the Death Star with 3803 and Tower Bridge with 4295 - I don’t really like either of those sets).
You can see some photos of the build process and completed model in my Flickr set but I will include a few shots here to highlight some of the best (and worst) bits of the build:
It wasn’t until I started building the set that I realised this is, amazingly, the first LEGO Star Wars set I’ve built (not counting the LEGO Star Wars Advent calendars in 2011 and 2012). This was, therefore, the first Darth Vader minifig I’ve collected but even better than that was the Emperor hologram that I didn’t know existed, let alone was in this set. A really nice touch.
Manual and boxes
Most modern LEGO sets come in numbered bags so that you can build the model in stages. This is useful for all sets but especially important for the models with thousands of pieces as you don’t want to open them all and spend days foraging around for the bit you need. This is the first set I’ve seen that comes not just with bags, but numbered boxes! The manual is also worth mentioning as it is spiral bound and weighs a ton. It also came in its own box.
This is another nice touch, a Star Destroyer in scale with the rest of the model so you can understand just how huge the Executor is supposed to be. Even when watching the films I hadn’t really noticed how huge this ship is supposed to be but the detail placard points out that it would have a crew of 280,735. This is a nice way of showing the scale and the miniature model is quite clever with hinges to form the shape and clear plastic arms to hold it to the side of the Super Star Destroyer.
This is the only negative in the set in my opinion. It’s the control room of the ship where a lot of the action in ‘The Empire Strikes Back’ takes place (particularly the scene where Vader briefs the bounty hunters, several of whom are minifigs in this set). The nice part is that it replicates this room perfectly with the walkway, sub-level computers, and sliding doors. The problem is that it uses a lot of stickers (which I hate) and that it is completely off scale with the rest of the model. In proper scale, this should be about 2x3 studs (or smaller) but it has been designed so minifigs can fit inside. Fortunately the whole thing is hidden under a beautifully designed lifting piece but I just dislike that this has been added to give it a ‘play’ element when it is clearly a collectors build rather than a toy.
This is an absolutely fantastic set. It took me around 3 days to build (due to being slightly ill and having other things to do) but is probably 6-8 hours worth of solid building. There are so many cleverly designed elements that it is bound to be unique for many LEGO builders. I particularly liked the use of coloured bricks in the interior sections in order to break up the grey making it easier to see where you were in the instructions.
The set is an absolute beast and I’d encourage you to take a look at the full photo set which shows it being built from start to finish. Now it’s time to wait until July for my next projects; the Lone Ranger sets and the new Lord of the Rings sets (including the Tower of Orthanc… can’t wait!)
When I first got my Apple TV, the main issue I had was that my artwork looked crappy for some of the TV shows I’d downloaded from places other than iTunes. I’d been using a combination of Google Image Search and screenshotting and cropping the iTunes Store to get artwork and it looked awful on a big TV. To solve that, I wrote a small script to fetch TV Show artwork from the iTunes Search API. They only display 100px artwork but with some URL fudgery I was able to get 600x600px artwork.
The project became a lot more popular than I imagined and I was soon inundated with requests to add new features such as searching across international iTunes stores and adding movie artwork. More recently, I’ve been asked to add iBooks artwork.
I had a bit of spare time this morning so I’ve updated the project page and added a fair few new features.
Media Types - I’ve extended the iTunes Artwork Finder to now work with not only TV Shows and Movies, but also iBooks, Apps, and Music Albums.
Resolution - I discovered that I was able to get higher than 600x600px artwork in some instances. Movies can be upto 1800x2400px and I’ve seen some TV shows at 2400x2400px. Apps will always be at 512px square or 1024px square depending on when the app was released or last updated. iBooks, Movies, and Music Albums are a bit problematic as licensing issues often prevent the high resolution artwork being made visible. I’ve left the link there as it does work with some (seems to depend on the studio) but there is a caveat listeed as I don’t expect you’ll get good results.
Countries - There are now 5 iTunes Stores that can be searched across; UK, US, Germany, Sweden, and the Netherlands. If you want your country added, just get in touch.
I’m pretty pleased with the update, particularly now that I’ve managed to get album covers and iBooks worked out (and I think the app icon search could be useful). Give it a try and let me know how you get on!
I took my girlfriend to the Warner Bros Studio Tour (which is entirely Harry Potter based) on Valentine’s Day and had a few observations I wanted to write about.
The Tour - If you’re a Harry Potter fan or interested in how movies are made, then it is a great tour. You get to see a large number of sets, props, and artwork along with a few interactive elements such as flying on a broomstick to see how ‘green screening’ works. The things that really stood out to me were how small some of the sets were and also how much effort they go to with some things (i.e. the Dursley’s house is on the backlot.. they found it easier to build a fake house than film on location). The highlight of the tour is a huge model replica of Hogwarts which took 72 man years to build. It really is stunning.
Queues - This is the first attraction I’ve ever seen which only lets you buy tickets in advance (you can’t just turn up on the day). On arriving, it was evident why; the place was packed! When you order your tickets, you choose a half hour window from which you are allowed to enter the attraction. We got there 45 minutes early so milled around the gift shop and the coffee bar but there were lots of other people doing the same (I’d estimate around 400-500 people). We spent a further 45 minutes queueing to get into the attraction which is slow going as there is a 10 minute cinema piece before hand. Whilst it was irritating to wait a while, it definitely paid off as this drip feeding into the studios means you enter the Great Hall (the first stop) with around 100 other people. This is the only ‘guided’ bit of the tour with someone pointing out various aspects of the set but then you are free to walk around the next bits at your own pace. It never really felt overcrowded despite appearances from the outside and I can understand why they chose this ticketing system.
Digital Guide - When I bought the tickets, there was an option to pay a bit more and get a digital guide and a printed guide. I did this expecting the digital guide to be something on a website or an interactive PDF but it was actually one of those things you walk around the tour with along with a headset. I didn’t use it, but I had a good look at it after I noticed one of the videos had iOS controls. It turns out there was an iPod Touch inside just wrapped in grey plastic which most likely had a battery booster and theft detection thing in it. I don’t know how they did it, but I saw one couple who had managed to get to the iOS home screen which confirmed it (along with the giveaway 30 pin connector on the base and the slight curved shine of a metal back inside). The guide itself is simply an iOS app that you press buttons on to get audio and information about (there is a full review on the Visitour website) but it seemed pretty good. Having said that, we didn’t bother using it. I think it would have been nice if the app could have been downloaded on to our own devices to be used later on (i.e. looking through the physical guide and having some audio to listen to along with it) but I was more intrigued by the use of iPod Touches as guides rather than a bespoke device.
WiFi - I didn’t use it, but I was impressed that there was free WiFi throughout the tour. Nice if you’re the sort of person that wants to upload photos as soon as you take them.
iPads - Not really an observation of the tour so much, but I saw a lot of people taking photos on their iPads (both the 10” and 7.85” models). This strikes me as very odd as I saw most of them had iPhones or other smartphones.
Commercialisation - If you’ve got kids, get ready to spend a lot of cash in the gift shop. They have nearly everything you can imagine with Harry Potter plastered on it and at a steep price as well (i.e. a small bag of Bertie Bott’s jelly beans is £9). My girlfriend pointed out that there wasn’t a single item for under £2 aside from postcards at 90p each. You kind of expect it these days but I’d find it genuinely fascinating to know how much money they make each day. In terms of stock, it’s the same stuff they sell at the Wizarding World of Harry Potter at Universal Studios (although it’s more expensive then buying in dollars - a Chocolate frog is $10 in the US but £8 in the UK).
Overall, it was an awesome day out and I’d highly recommend it. There was plenty to see and do and a lot of the sets and props are incredibly impressive. Just be ready to queue at the beginning, and empty your wallet at the end.
The problem is that CACurrentMediaTime() has a fatal flaw. Whilst it’s designed to be a counter, it only actually works whilst the iPhone (or iPad) is active. Here is how it’s described by Apple in their documentation:
Returns the current absolute time, in seconds. A CFTimeInterval derived by calling mach_absolute_time() and converting the result to seconds.
Further inspection of mach_absolute_time() gives us very little (documentation is very sparse). On Mac OS X, mach_absolute_time() is based on the last time the device booted (it gives you the number of seconds since you turned your computer on) so it seems prudent that this would be similar on iOS. Apple give some cursory examples of how to convert mach_absolute_time() from nanoseconds into seconds and in doing so point out that “the function is CPU dependent” and needs to be converted by the system rather than by constants. There is no mention of how it all works but the general consensus seems to be that it’s uptime.
Apart from it’s not. Unfortunately for me, it took an App Store release for this bug to be noticed.
See, the interesting thing about mach_absolute_time() is that it appears to be the ‘active’ time of the device, that is to say it’s the number of seconds that you iPhone has been active. However, it’s more sneaky than that as putting your device in standby mode will actually leave the device ‘active’ for a few minutes whilst core components are turned off. In effect, if you are relying on mach_absolute_time() and, by extension, CACurrentMediaTime(), you’ll find that the ticks suddenly pause when your iDevice has been in standby for a few minutes.
So how did this come to light? My game, WallaBee, required a way to count time accurately independent of the system clock (which can be changed by the user). I built a system which allowed me to get the time from my server, account for some lag, and then render elements from CoreData at specific times based on what I believed was a steady ticking in seconds. When the app was sent out to my testers, it seemed to work but occassionally putting the device to sleep and then resuming would lead to some odd behaviour; the clock was running slightly behind. I tried replicating this several times to no avail and eventually left it ‘as is’ since it seemed to be occurring very infrequently and there was no way to work out exactly was happening.
After the code made it into the App Store, there were a few more people commenting that the Store seemed to be running a few seconds behind (or in some cases, minutes behind). I again ran some builds and couldn’t find any errors and it was only after considering that my Xcode build and Testflight build (read “Ad Hoc”) could be different that I discovered the error; any build that wasn’t tethered to my laptop suffered from a slowing down of time. As the Store automatically corrects itself at ~8 minute intervals, and the bug only presented itself after a few minutes of standby, it was quite tricky to replicate exactly.
To test it, I built a very crude mockup app that would present a UIAlertView when you came back from standby mode with the number of seconds perceived by CACurrentMediaTime() and the number of seconds derived from deducting two NSDates (which we couldn’t do in the production app as changing the system clock alters that - it’s good for testing though). Sure enough, after leaving the app in the background whilst the device was on standby for a few minutes, it was apparent that CACurrentMediaTime() was pausing. I did another mockup including mach_absolute_time() and that returned the same result; a pausing of the clock when the device was in standby for a while.
After a lot of googling, I found a solution that was based on the device uptime rather than an arbitrary ‘absolute’ time:
This returns a t_time (read int) of the number of seconds since the device was last powered up and so I was able to slot this into my old code in place of CACurrentMediaTime().
The moral of the story? Always test on an Ad Hoc build that isn’t tethered to Xcode. It’s a pain but the crucial thing in this was that the Xcode debugger was keeping the iPhone alive and that meant I was never able to see that CACurrentMediaTime() was pausing itself. The other thing to do is to read Apple documentation carefully. At no point do they specifically say that mach_absolute_time is based on uptime or that it counts up sequentially, but forum posts and other developers blogs had created that perception based on their own findings and those of the method on OS X. It always pays to be careful and understand fully the methods you are calling.
Fortunately (or not), there was a bug with iOS 5 in the version of WallaBee that was submitted to the App Store and so this fix was bundled in with an expedited review. Of course, that update has now been ‘In Review’ for over 24 hours so we’re not out of the woods yet but at least I’m now using a timer that actually counts up…
Update: It turns out CACurrentMediaTime() has a significant bug in that it doesn’t count up when an iPhone is in standby mode. Check this update for a better solution.
If you’ve played WallaBee you’ll know that one of the key areas of the app is the Store, a place where you can buy items with the app currency you collect. The Store has a 3 x 4 grid of items with a timer under each; when the timer runs out, a new item is displayed for purchase. This all sounds straightforward, but when the WallaBee API started getting 3 million hits per day, the Store was one of the first areas to suffer. In this article, I want to run through a few of the problems I experienced when building it the first time, and go into details on the improvements I’ve just added in v1.1.5 of the app which will be available this week.
The Original Plan
In my mind, the Store was going to be fairly simple. It had to be the same for everybody so I’d set up a CRON job that would populate a database table with the upcoming items. Every minute, a check would be performed and items would be added to make sure there was something in every spot until the next time the script ran. Every item had a start and end time that was fixed but had a random amount of seconds (between 10 and 45) so that each item would ‘run out’ at different times. Whenever a player visted the Store, an API call would retrieve the items at each position and do some basic math to work out how long it would be until the position needed to be restocked. Finally, there was an API call to reload just a single position which would be called when an item ran out and a new one was needed. Simple!
The problem with this is that WallaBee became popular and the database bore the brunt when a new item was released and the players descended on the Store. This meant that, when a position needed restocking, there could be thousands of requests in the same second all asking the database to tell them what that item should be. Those kinds of numbers don’t work well (it’s basically a denial of service attack) and so the Store would gradually become emptier and emptier as the network activity indicator struggled and the database slowly spat out what items should be where. Another issue was timing; there was a slight overlap between expiration and start times of items and so clever developers could look and work out when a new item was appearing in the Store upto 15 seconds before the item appeared (leading to an unfair advantage). In addition, if the network connection was slow, some players could be behind the live Store by 10 seconds or so meaning they would be at a disadvantage when something new appeared.
Clearly there was work to be done.
I had three key problems to solve.
The Store had to be synced for everybody. I wouldn’t accept more than a 500ms gap between players regardless of their connection speed.
It had to be secure with no chance of seeing what item was coming in advance, even if you sniffed the network traffic with something like Charles.
It needed to be fast. This meant no database calls and as few API calls as possible, especially during peak times.
In addition, the solution needed to be scalable as I would be adding multiple stores in the next major version of the app. The app would have to be able to display around 80 items at a time rather than 12.
The New Plan
My solution was that the server would generate a physical file every minute that showed all of the updates for the next 10 minutes. When a device requested the Store, it would download this file (no database calls) along with a synchronisation timestamp. This file would be unpacked on the device and each item would be stored locally so that the Store could continue on without making any network calls. At some random point before the 10 minutes was up, the device would request the next 10 minutes worth of data and unpack it silently in the background.
Whilst it sounded good on paper, it would require a lot of work to get everything working correctly. Each piece is inter-connected but I’ll try and explain the general timeline of how it works along with a bit of code.
The first thing that needs to happen is that the server has to generate 10 minutes worth of items. I created a new table that would hold the item objects and wrote a basic CRON job that went through each position and randomly chose an item1 along with a random shelf life between 45 seconds and 4 minutes. This runs every minute and ensures that there is always 10 minutes worth of items coming up. A separate CRON job then runs and compiles these items into a single JSON file which is then encrypted with a military grade cipher (more on that shortly). This file is stored locally and updated every minute. The end result is that you can request the file at any time and always be sure that you have the next 10 minutes worth of items.
One of the key things I wanted to ensure was that the Store was secure as I wouldn’t want anybody to sniff the network traffic and see that a new item was coming out in 7 minutes time (it should always be a surprise). To that end, the file is encrypted using AES-256 before being encoded in Base64 for easy transporting. To do this in PHP is fairly simple:
The thing that most people miss off is the padding as the data to encrypt has to be a multiple of 16 characters and the characters you use for the padding follow a specific rule; they use the character code of the number of characters you need to pad (for example, if you have to use 7 characters of padding, you’d do it with 7 x chr(7). Another key thing was to use ‘cbc’ as the mode as the default ‘ecb’ found on many tutorials doesn’t work well on the iPhone.
The other key feature that needed to be implemented was that the iOS device should be synced to the server time so that all players would be shown the items at the correct times; we don’t want players to be behind or ahead even though the API would stop anybody from purchasing an item that isn’t released yet.
I looked into a number of options for time syncing but many of them use the built-in clock on the iPhone. This is no good as a player could simply advance their clock manually to see future items. Instead I opted to have the main Store file return a Unix timestamp of the time of the request. This is simple in PHP:
The issue with this is that the time of the request will vary depending on how slow the uplink connection is on the device, and we need a way of accurately monitoring how long it took to download so we can add an offset.
I’ve been using MKNetworkKit for my iOS networking needs (although I’m planning on switching to AFNetworking in the next release) and it provides a useful block-based method on network operations called onUploadProgressChanged. This provides a double which tells you, as a percentage, how much of your upload is done. When it gets to 1.0, that means you have successfully ‘hit’ the API which should tally up to the $_SERVER[‘REQUEST_TIME’] on the server side2.
Now we know exactly what time we hit the server, we need to start some form of timer so we can see how long it takes until the download completes. To do this, we use CACurrentMediaTime()3. This returns a CFTimeInterval which is roughly the amount of time since your device was rebooted; think of it as a UNIX timestamp that resets every time you start up your phone. I get the current media time upon the successful upload completion, and when the download is complete I get it again and subtract the difference (so I can see, for instance, that the download has taken 572.42ms). We then add this to the timestamp retrieved from the server to get the current server time; we’re now in sync!
Rendering the UI
We have the next 10 minutes worth of items stored locally and we know the exact server time, now we just need to render the UI. To do this, we’ll need a timer that runs continuously in the background to tell us what the current time is; we use this to get our items from our local store and render the progress bars underneath each shelf. The obvious choice is NSTimer, but there are a few gotchas. Firstly, if you create an NSTimer which is targetting ‘self’, you’ll create a retain loop; the view controller will never be released until the timer is invalidated4. Secondly, I’m using a UIScrollView with the store and any touches caused the NSTimer to pause (which may account for the time discrepency in older versions). To fix that, you need to add your timer to the main run loop as so:
We now have a timer that ticks every second but I found it important to use our old friend CACurrentMediaTime() again rather than incrementing a timestamp. The reason for this is that the user may switch tabs, receive a phone call, or leave the app. In those situations, you need to be ready to resume when they come back and, presuming that they’re within the window of how much data you have loaded, you can just kick off without reloading everything. The problem is, if you increment the timer every tick, you’ll start deviating from the start time if you jump back and forth between tabs as the timestamp is always rounded. By storing the CACurrentMediaTime() and the original timestamp when you start your first timer, you can be 100% accurate on your times by working out the number of seconds between now and the original CACurrentMediaTime() and adding them to your timestamp.
With every ‘tick’ we need to update the UI. This is fairly straightforward and is a case of looking at each position, working out the percentage remaining, and applying that to the progress bar. When an item is due to run out, simply fade it out a second before it expires and on the next tick fade it back in. This leads to seamless animations where before there was a fade out, network request, then gradual fade in. The results were so stark in comparison that I had to slow down the change animation as, without the network lag, it was too quick!
One final improvement I made was that the ‘ticks’ only happen when you are viewing the Store. Previously, the Store would continuously update in the background (including network requests) leading to a waste of CPU and battery life and making the rest of the app feel sluggish. Now, as soon as you navigate away, the timer is invalidated and nothing is updated. When you come back, the UI is refreshed and the timer is restarted (accurately as mentioned above).
The only thing we need to remember to do periodically is update our local store. When the Store is first loaded, I choose a random time between 6 and 9 minutes to perform an update. This is to try and spread out the number of requests to the Store file as typically we get 50x more users online when a new item comes out. If they all reloaded the Store at the exact same times we’d have hundreds of API requests in the same second still (admittedly it’s less of an issue as they aren’t hitting the database but it pays to spread the load). If the network connection fails or there is a server problem, the Store will try and reload after 5 seconds until such a time that it gets data. Crucially, the Store will keep going until it runs out of items at which point it stays bare until it gets back on track. To account for any deviations, the time sync is also performed on these updates.
The new Store is far superior to the old one in every way. The server is more stable, the data is more secure, and the UI is much snappier. With the changes to the way the Store UI was rendered, the rest of the app feels faster as well and load on the server during peak times should be substantially reduced. Crucially, an issue that has been present for a while with crashes when switching between apps has finally been resolved now that the NSTimer code has been rewritten.
It’s been quite a journey getting to this point but I’ve enjoyed learning about time syncing, encryption, and keeping time on iOS. As with many things, this is a progressive update and is a reminder that there is always more to learn.
Ok, when I say “randomly chose an item” it’s a bit more complex than that. Items are weighted based on release time, set, pricing, and so on and there are a number of custom overrides (i.e. Christmas is weighted down so you hardly see those items whilst the One Set To Rule Them All is weighted up as it is a huge collection and takes people longer to complete). In future versions, there will be multiple stores that each have their own rules (i.e. there might be a Store which only has items that are over 6 months old or only items from a particular series of sets). ↩︎
It’s not exact but it’s within ~200ms which is accurate enough for this. ↩︎
CACurrentMediaTime() is specifically designed for gaming where you need to have time independent of the system clock and that doesn’t need to be reconciled with an actual world time. For example, the early versions of Tiny Tower had a bug in which you could move your system clock forward in order to get around things like “wait 3 hours for restocking”. They now start a CACurrentMediaTime() when you open the app and this is used to track time.. every second, it is checked and the overall time spent is worked out so it knows when 3 hours has passed, not when the timezone says 3 hours has passed. ↩︎
I hadn’t realised this in the previous version and I had an NSTimer for each position of the Store! This lead to a large number of unexplained crashes as memory ran out. Lesson learned. ↩︎