{ "version" : "https://jsonfeed.org/version/1.1", "title" : "Donald Haysʼ Blog", "home_page_url" : "https://donaldhays.com/", "feed_url" : "https://donaldhays.com/feed.json", "favicon" : "https://donaldhays.com/apple-touch-icon.png", "author" : { "name" : "Donald Hays", "url" : "https://twitter.com/Dovuro", "avatar" : "https://donaldhays.com/img/avatar.png" }, "authors" : [ { "name" : "Donald Hays", "url" : "https://twitter.com/Dovuro", "avatar" : "https://donaldhays.com/img/avatar.png" } ], "language" : "en-US", "items" : [ { "id" : "b6eaf8c6-08dd-45f9-bc35-421c240bfb79", "url" : "https://donaldhays.com/2023/04/02/updated-snake-and-bubble-factory/", "title" : "Updated Snake and Bubble Factory for Game Boy", "content_html" : "
It feels odd, releasing version updates for Game Boy games years after their\ninitial release, and decades after the system was discontinued, and yet, here\nwe are!
\n\nI’ve made updates to both my Snake and\nBubble Factory games.
\n\nSimilar to my previous update to Snake,\nI have updated Bubble Factory for Game Boy to\nversion 1.1. This update fixes the same issue, where some emulators and flash\ncarts wouldn’t save high scores correctly, because the game was configured as\na non-standard cartridge type.
\n\nAlso, like with Snake, I took the opportunity to refine the build process to be\nsomewhat more standard. Building the game now expects SDCC to be in your PATH,\ninstead of requiring you to place a copy of it in a specific location relative\nto the project directory.
\n\nFinally, there was a best-practice change, where I now wipe sprite object\nattribute memory before enabling sprites for the first time. Failing to do so\ncan result in an issue where corrupted, random sprites appear on screen. I’ve\nnever noticed this issue actually manifest in this game, but it was trivial to\ndo the right thing, so I did.
\n", "date_published" : "2021-04-22T09:20:09-07:00" }, { "id" : "df9e23aa-4ba8-4724-b71b-3a74e4d88f9f", "url" : "https://donaldhays.com/2021/03/09/updated-snake-for-game-boy/", "title" : "Updated Snake for Game Boy", "content_html" : "It is with great embarrassment that I’m pleased to announce version 1.1 of my\nSnake game for Game Boy!
\n\nThis release fixes a single issue: high scores wouldn’t save correctly on some\nemulators and flash carts.
\n\nOriginally, the game was configured as a ROM+RAM+Battery cart type. As it turns\nout, there was—as I understand—never a commercial release of a game with that\ncartridge type, which means emulators don’t have a reference for how exactly it\nshould behave. As a result, even though every emulator I tested it on at the\ntime worked, I was unknowingly relying on unspecified behavior, and it turns out\nthat it doesn’t work everywhere. I have since changed the game to use the MBC5\nmemory bank controller, which is well-documented and supported. The game is\nstill 32 kilobytes, and if you have a save file from an emulator that supported\nthe old version, that same save should still work, but saving will now work on\nmore emulators and flash carts.
\n\nAlso, I moved the initial stack pointer from the end of high RAM to the end of\nregular RAM. This doesn’t make a practical difference for this game, but it’s\njust better practice in general: high RAM is fast, but not in a way that the\nstack can take advantage of.
\n\nFinally, updating the game involved a sizable commit\nto address the surprising amount a project for a long-dead platform had rotted.\nFirst, I switched from a custom build script to a more standard Makefile. The\nupdated build process also expects you to install RGBDS externally, rather than\nhave a copy of it in the project folder structure. These changes weren’t\nnecessary, but are better practice. But more importantly, RGBDS itself has\nbeen evolving over time, and I addressed some deprecations and language changes.
\n\nAlso embarrassing, Bubble Factory suffers the exact same save problem. I’ll be\nfixing it, too, later.
\n", "date_published" : "2021-03-09T10:50:34-08:00" }, { "id" : "90379d18-3074-4fb9-a4c3-9c88b5eb08f0", "url" : "https://donaldhays.com/2019/12/30/playdate-art-scale/", "title" : "Playdate Art: Scale", "content_html" : "As anyone who follows me on Twitter has noticed,\nI’ve been mildly utterly obsessed with Playdate, an\nupcoming handheld game system by Panic. As of the time of\nwriting, the device has yet to be released, but the Developer Preview program\nwill be beginning soon. I have spent spare time these past few months\nexperimenting with art and code in anticipation of the SDK, and thought I would\nshare my thoughts and observations over a few blog posts, in hopes that some of\nit may be helpful to developers and designers. In this first post, I want to\ntalk about making art for Playdate, with a particular focus on scale, or\nchoosing the size to make your art tiles and sprites.
\n\nI would also like to eventually talk about things like techniques for 1-bit\nblack and white art, but since this post clocks in at about 1,800 words, I think\nI’ll have to save that for another day!
\n\nNote: as of writing, I have no access to the SDK, and not only do I not have a\nPlaydate, I have never even seen one in person. I’ve made myself some software\ntools to let me see my Playdate art at the correct scale, but you should consider my lack of\ndirect experience with the hardware when reading this. It’s entirely possible my\nrecommendations are grievously ill-informed!
\n\nAt first glance, Playdate looks very much like a Game Boy. It has a black and\nwhite display, a d-pad, and two action buttons. But it’s also got a menu button,\na USB-C port, and a crank, but on first impression it looks very familiar.
\n\nThat familiarity piqued my attention before anything else. I’ve always had a\nstrong fondness for the Game Boy, so much so that over the past few years I’ve\nbegun doing homebrew Game Boy development as a hobby. A few years ago, I\nreleased a game called Bubble Factory,\ninspired by Game & Watch games and the later Game & Watch Gallery series of\nGame Boy titles.
\n\nWhen Panic announced Playdate, I knew I wanted to develop for it. But I also\ndidn’t want to wait for the SDK, so I set to work learning everything I could\nabout the device. I wrote a set of C APIs that provided a Playdate-like\nenvironment, and then wrote an SDL backend for the APIs to let me run code for\nthat environment on my Mac, with the thinking that once I get the SDK I could\nyank out the SDL backend and replace it with an actual Playdate SDK backend.
\n\nI’ve programmed various art and gameplay experiments since then, one of which is\na version of Bubble Factory for Playdate.
\n\nOne of the first things that may stand out to you about the Playdate version\nversus the Game Boy version is the size: Playdate’s screen has a 400x240\nresolution, versus the Game Boy’s 160x144. If you’ve done any development for\nold systems, or if you’ve designed retro-style pixel art games, this resolution\nmay at first feel like it gives you a huge canvas to work with, but it’s\nimportant to keep things in perspective. Even though Playdate’s resolution is\nreally high, the display’s physical size is somewhat comparable to the Game Boy,\nmeaning the device has a high pixels-per-inch ratio. In fact,\neven though Playdate’s display is wider than the Game Boy’s, and slightly larger\nacross the diagonal, it’s actually a little shorter vertically.
\n\nThis is why I wanted to make this post. If you design for Playdate at the scale you\nwould for retro systems or retro-style games, you may accidentally make art that’s\nuncomfortably small when viewed on the screen, so I want to offer some\nobservations and suggestions.
\n\nGraphics processing hardware has long been a feature of game systems, but before\n3D acceleration took off we had 2D sprite hardware. Sprite processors were\ncapable of blitting small 2D images to a screen significantly faster than CPUs\nwould otherwise be capable of. Often, these systems would be built around 8x8\npixel tile images, which would be composed together to form the screen image.\nTiles could be arranged in a grid to form the background map, and tiles with\ntransparent cutouts could be layered on top for sprites. 8x8 pixel images were\nrather small, so many games would use 2x2 arrangements of these tiles together\nto form a base 16x16 pixel size for tile maps and sprites. These 2x2 tile\narrangements were called metatiles, but I will confusingly just refer to them\nas tiles from here on out, just understand that on systems like the NES, 16x16 pixel\n“tiles” were actually 2x2 arrangements of 8x8 pixel native tiles.
\n\nMany games were built with 16x16 pixel sprites and map tiles. On the NES, with\na resolution of 256x240, a background map made of 16 pixel tiles would give you\na 16x15 tile viewable field size.
\n\nThe Game Boy also had 8x8 pixel hardware tiles, and so 16x16 pixel\nmap tiles and sprites continued to commonly appear, despite the Game Boy’s lower\nscreen resolution of 160x144.
\n\nWhile sprites and map tiles were commonly 16x16 pixels, it was also common to\nmake fonts fit within 8x8 pixel tiles. Usually, these fonts would have a cap\nheight of 7 pixels, with 1 pixel remaining on the bottom for descenders.\nExamples of these are highlighted on both of the earlier screenshots.
\n\nBecause these sizes were so common, they continue to be strongly associated with\nretro games today. Shovel Knight,\nfor example, is a modern retro game, and while most sprites are larger than 16\npixels, it continues to use an 8-pixel monospace font and has maps made of 16\npixel tiles.
\n\nSince Playdate is so evocative of older systems, then, it may be tempting to use\nsimilar sizes when designing for it. But I feel that would likely be a mistake.\nBecause the pixel density is so high, an 8-pixel font or 16-pixel character will\nlook very small on the screen.
\n\nIn fact, art of any given size will appear about half as big as it would on\nthe Game Boy. Because of that, consider drawing larger assets than you might\notherwise if you were designing a retro-style game. A 24-pixel character on\nPlaydate will appear slightly smaller than a 16-pixel character on the Game Boy,\nand a 32-pixel character on Playdate will be comparable to the Game Boy’s 16.
\n\nIf you have experience designing for smartphones, making Playdate art versus art\nfor retro systems feels almost like designing assets for a “Retina” display as\ncompared to a “1x” display.
\n\nThis scaling advice applies with particular emphasis for fonts. Sharp though the\ndisplay may be, an 8-pixel (or smaller) font will appear very small, and may\nbe difficult to read, especially for body text. I previously tweeted out an\nearlier mockup image of Bubble Factory, and\nNeven Mrgan at Panic\nuploaded the image to a device.\nBut the font for “Score”, “High Score”, and “Miss” was smaller than it is today,\nand Alex Guichet observed that it may be too\nsmall, which Neven confirmed to be the case.
\n\nNow, the font today is larger, but still pretty small 😬, so here I go ignoring\nmy own advice, but I feel a reasonable exception exists for minor text elements.\nIf you look at the clock in Crankin’s Time Travel Adventure,\nyou’ll see that the “PM” font is far smaller than 8 pixels, but the time font is\nmuch larger. Important text, including dialog, scores, and health, should lean\ntowards larger fonts.
\n\nBecause Playdate uses a CPU-based bitmap renderer instead of dedicated sprite\nhardware (note: I suppose I could be wrong on that, but as I understand it’s\nthe case), you’re not really boxed into grid-based games with tiles that are a\nmultiple of 8 pixels in size—Crankin’s Time Travel Adventure certainly isn’t—but if you\nmake a game based on a grid, you need to choose a base tile size.
\n\nI’m going to refer to the number of tiles on screen as the field size. The\nfield size has an inverse relationship to the tile size. The larger your tiles,\nthe fewer of them you can fit on screen. For example, a hypothetical 100-pixel\nscreen could fit 4 tiles if they’re 25 pixels each, but 5 tiles if they’re 20\npixels.
\n\nField size is also independent from map size, which is the overall horizontal\nand vertical number of tiles in a level. Field size refers to the subset of a\nmap that can be viewed on screen in a given moment. If the map size is larger\nthan the field size, then scrolling will be necessary to view the whole map.
\n\nSmaller fields tend to feel more cramped, because you can’t see as many tiles\naway from your character, but larger fields require smaller tiles, which can be\nharder on the eyes. Therefore, you need to strike a balance between the two.
\n\nWith 16 pixel tiles, the NES has a 16x15 field size, and the Game Boy has a\n10x9. If you played Mega Man games on both the NES and the Game Boy, you may\nrecall that the Game Boy games tended to feel more cramped, because sprites\nand map tiles were the same size as on the NES, but the field size was\nsmaller on the Game Boy.
\n\nSince Playdate’s screen size is comparable to the Game Boy (especially along the\nvertical axis), you may want to pick a tile size that gives you a\ncomparable field size. If your tiles are 24 pixels, your field would be 10 tiles\ntall, while 32 pixels would give you a field 7.5 tiles tall. You can also choose\nsmaller or larger tiles, with the natural tradeoffs for viewing comfort versus field size.
\n\nYou may also want to consider non-square tiles. When I designed a Chess set,\nI made 24 and 32-pixel variants. I really liked the 32-pixel pieces, but a Chess\nboard is 8 squares tall, and so it wouldn’t fit a 7.5 tile field. But by\nsquishing the y-axis and letting the pieces overlap the squares above them, I\ngot the whole board (and then some) to fit while holding 32-pixel pieces, and it\ngives the board a nice perspective feel, too. Be creative!
\n\nI spent much of this blog post directly comparing the Game Boy to Playdate, but\nI want to emphasize that Playdate is very much its own thing, so don’t feel\nconstrained by old sizing conventions. Do what feels right for your game, just\nbe aware that the screen has a high pixel density, so you should consider\nwhether you’re designing something that’ll appear too small.
\n", "date_published" : "2019-12-30T12:49:35-08:00" }, { "id" : "fa79ca9d-0c86-49ef-a624-a0cbdd4e4126", "url" : "https://donaldhays.com/2017/06/30/announcing-bubble-factory-for-game-boy/", "title" : "Announcing Bubble Factory for Game Boy", "content_html" : "Is it weird to release a new Game Boy game in 2017? It’s not a huge game, but\nI’m releasing a new game called Bubble Factory!
\n\nThis follows the Snake game I made last year. That game was\nwritten in Z80 assembly, while this game was written almost entirely in C.
\n\nIt was really educational to write a game in assembly, but I found C to be\n(unsurprisingly) more productive. I think I’ll probably stick with C if I write\nany more Game Boy games.
\n\nThe source is available if you’re\ninterested in seeing how it works.
\n", "date_published" : "2017-06-30T12:39:43-07:00" }, { "id" : "387d349d-ae07-4563-a5f3-f3cc1d7843a8", "url" : "https://donaldhays.com/2017/06/01/added-a-json-feed/", "title" : "Added a JSON Feed", "content_html" : "It’s been a while since my last post, and I only have a brief update today. I\nadded support for JSON Feed to this site. You can view\nit here. It joins the existing\nAtom feed.
\n", "date_published" : "2017-06-01T02:22:59-07:00" }, { "id" : "d66af24b-e73d-4169-9946-c1c2e342ee06", "url" : "https://donaldhays.com/2016/01/16/minor-sunset-controls-update/", "title" : "Minor Sunset Controls Update", "content_html" : "I made a minor update to Sunset today.
\n\nFor iOS devices: Sunset now recognizes touch events on its gamepad, and will use\nthose instead of click events if possible. This eliminates the 300 millisecond\ninput latency you otherwise get. This means it takes about 6 fewer seconds to go\nfrom one side of a map to the other. Speedrunners rejoice!
\n\nFor desktops and laptops: Sunset has long supported keyboards through arrow\nkeys, the space bar, and the escape key. Today I also added support for WASD for\nmovement and Q and E for turning. This is the first time you’ve ever been able\nto strafe in Sunset. Such flexibility!
\n", "date_published" : "2016-01-16T06:54:59-08:00" }, { "id" : "6ffee588-0e36-4067-9635-24816c7b53a9", "url" : "https://donaldhays.com/2016/01/14/uploaded-sunset-again/", "title" : "Uploaded Sunset Again", "content_html" : "I just re-uploaded Sunset to my site.
\n\nBack in 2007, Apple released the iPhone. Apple didn’t announce the App Store\nthen, saying instead that web apps would be the “sweet solution.” People weren’t\nterribly keen on that, but I thought JavaScript had much to offer on the iPhone,\nso I set out to make a game that pushed the boundaries as much as I could.
\n\nI decided to make a 3D turn-based RPG. Sunset was the result. I released it in\nJanuary of 2008, shortly before Apple announced the iPhone SDK. The first wave\nof native games easily trumped my game’s visual fidelity, but for a very brief\nwindow of time I honestly felt I had put something out that was at or near the\ntop of the heap of what developers could make the iPhone do.
\n\nMuch has changed since then. WebGL is a thing, enabling browser games to far exceed\nwhat I could do in a Canvas tag. Phones have gotten orders of magnitude\nfaster. I’m pretty sure my iPhone today is faster than the iMac I developed\nSunset on. In fact, because of how fast modern phones are, I made a minor change\nto Sunset today before uploading: as a performance optimization in 2007 I only\ndid a 3D raycast against every fourth column of pixels, leading to a\nstair-stepping pattern when\nviewing walls at extreme angles. I have removed that resolution limit, so your\ndevice will now raycast all 320 glorious columns of pixels. Marvel at the\nfidelity!
\n\nI played the game again to make sure it still worked (age has a funny habit of\nbreaking old software, even though the software itself didn’t change). I grimace\nat a lot of my bad art, but I think the gameplay—simplistic though it\nbe—holds up pretty well. I like the difficulty curve, level progression,\nand item stats. You struggle for a bit, then get a nice weapon upgrade and feel\nlike an invincible God, then you move on to the next zone and things get hard\nagain.
\n\nSo if you want to play a small, free game that might keep you busy for a few\nhours, give it a try!
\n", "date_published" : "2016-01-14T12:54:09-08:00" }, { "id" : "1752c69a-2251-4b97-bba1-aa3007a02fb2", "url" : "https://donaldhays.com/2015/08/29/maidenhead-converter-220221-and-the-importance-of-qa/", "title" : "Maidenhead Converter 2.2.0/2.2.1 and the Importance of QA", "content_html" : "Maidenhead Converter 2.2.0 went live about a\nweek ago, and—due to a bug—2.2.1 followed soon after.
\n\nThere are two features in these releases, and several bug fixes. I added the\nability to pick a format for distances, allowing you to choose between Metric\nand Imperial. This is presently only used for the accuracy label when tracking\nyour location, but it’ll also be used for other features I want to add later.
\n\nI also improved VoiceOver accessibility support throughout the app. You can\nnavigate menus and work the keypads via VoiceOver. I don’t know if I really have\nany audience for VoiceOver, but it’s a good thing to do and I wanted to practice\nimplementing it anyway.
\n\n2.2.0 also fixed a few very minor display issues. A few views weren’t aligned\nwell on all devices, and text could clip on some others. Also, iOS 9 will change\nthe system font from Helvetica Neue to San Francisco. When displaying text in\niOS, you can ask the OS to give you the “system font” of a specific weight and\nsize, but there were a few places where I was explicitly asking for Helvetica\nNeue, so I replaced those calls with asks for the system font.
\n\nUnfortunately, 2.2.0 also broke the in-app purchase for the ad disabler. Folks\nwho already bought the ad disabler still had ads disabled, but people who didn’t\nalready have it couldn’t buy it.
\n\nHow did this happen? Didn’t I say in my last post that I have a Runbook that I\nuse to test every part of the app? Yes, and I ran it for 2.2.0, and every other\npart of the app worked, but the store didn’t, and I shipped anyway. Why?\nBecause I couldn’t find any reason in the code for the purchases not to work, so\nI decided to bet that I wasn’t able to do purchases in dev because the sandbox\niTunes Store was down, which is something that happens from time to time. Once\nthe app went live and purchases didn’t work with the real App Store, I knew that\nbet was wrong.
\n\nAfter poking around for a long time, I discovered the bug appeared when I\ntransitioned to Swift 1.2. That version of Swift added a built-in Set type, and\ncalls that used to take the Objective-C NSSet type changed to take the new Set\ntype, so I changed one line of code in the store from:
\n\n\n\nto:
\n\n\n\nSo all is good, yes? No. For some reason, despite the fact that the syntax is\nvalid, and logging out the resulting set appeared fine, for whatever reason when\nthat bridged back to Objective-C for StoreKit, the set was invalid in some way,\nand a “could not connect to the iTunes Store” error would be produced. The\nsolution ended up being to change the line to:
\n\n\n\nWhich also compiles fine and looks fine when logged out, and by all respects\nshould be functionally identical to the previous line, but it was the\ndifference between a working store and a broken one. I’m guessing there’s a\nSwift bug here, and when I update the app to Swift 2.0 I think I’m going to try\nboth constructions and see if only one still works, and if so file a bug.
\n\nSo the lesson I need to take away from this is that I really do need to pass all\nmy QA checks before shipping an app, no matter what.
\n", "date_published" : "2015-08-29T03:41:29-07:00" }, { "id" : "d97a8a19-2b28-4d92-ac26-b5f13d45ec10", "url" : "https://donaldhays.com/2015/02/03/maidenhead-converter-211/", "title" : "Maidenhead Converter 2.1.1", "content_html" : "Maidenhead Converter 2.1.1 is now live. This\nwas largely a refactor and bugfix release, there aren’t any new features.
\n\nI like using Maidenhead Converter as a testing ground for ideas, patterns and\npractices that I apply to my work on EventBoard.\nMaidenhead Converter is small and simple, but does a real task.
\n\nRecently, I’ve had a big focus on QA. The app now has a suite of unit tests, and\nthose tests helped uncover some of the bugs that I fixed. The bugs tended to be\non the app’s edge cases, but they were real, and I hadn’t caught them before.
\n\nI’ve found that internal data and processes are easy enough to write unit tests\nfor, but views and view controllers seem quite difficult to test without doing\nsome pretty bad contortions. I would like to figure out a good, straightforward\nway to write automated tests for the UI layer, but I don’t have one right now.
\n\nWhat I do have is a Runbook. A Runbook is a document that describes every\nbutton and feature and state of the app, and says how they should work. It’s\nsimilar to the monolithic design document that software under the waterfall\ndevelopment model gets, except the Runbook is developed alongside the app,\ninstead of before. Before submitting a release, you treat the Runbook like a\nchecklist, examining everything in the app and making sure it works as intended.\nWhile obviously far more time-consuming to execute than automated tests, it\nstill did good for my confidence in the quality of the app.
\n\nNow that this release is done, I intend to do 2.2.0, which will include some\nnew features.
\n", "date_published" : "2015-02-03T10:50:55-08:00" }, { "id" : "9ee40e0a-3f33-4e4b-82cd-95b52216c116", "url" : "https://donaldhays.com/2014/12/16/enum-errors-in-swift/", "title" : "Enum Errors in Swift", "content_html" : "Brad Larson of\nSunset Lake Software wrote a\nblog post\ncalled “Why we’re rewriting out robotics software in Swift.” The article is a\nworthwhile read, and explains that an audit of their Objective-C code history\nrevealed that approximately 40% of the shipped bugs would have been prevented by\nusing Swift. Which is really interesting.
\n\nI would like to focus on a different part of the article, however. It’s actually more of an aside\nin the article itself, but it was something that really stood out to me: the\nuse of enums instead of NSError in Swift. Brad goes into more detail on the\nsubject in a mailing list post.\nAfter having played with it myself, I think using enums for errors is a really\nbig win, and I intend to use the pattern in my own Swift code going forward.
\n\nNSError is used in code built on the Foundation framework for recoverable error\nsituations. By merely receiving an NSError object, you know something went\nwrong, and you can inspect the object to learn more detail about what happened.\nA good writeup on NSError can be found at NSHipster.
\n\nUnfortunately, constructing and inspecting NSErrors can be cumbersome. To create\nan NSError, you need to specify a domain and a code. The domain should be a \nreverse DNS-style string, like “com.company.app”. The code needs to be an\ninteger that’s unique within the error domain. The domain and code tend to be of\nlimited usefulness when using NSErrors later, but you need to supply them when\ncreating NSError objects anyway.
\n\nThe more-often useful information in an NSError lives in its userInfo\ndictionary. You provide values for a few system-defined keys like\nNSLocalizedDescriptionKey, and you can attach any additional objects you wish\nto the same dictionary. I often need to refer to documentation to remember\nNSLocalizedDescriptionKey, and attaching extra information to the dictionary\nrequires you to keep track of the keys you use in order to consume them later.\nPicking apart an NSError very frequently involves trips to a header file or\nframework documentation.
\n\nUsing Swift enums nicely addresses these complaints.
\n\nSo what does an enum error look like? Here’s an example of a hypothetical error\ntype for interacting with an API server.
\n\n\n\nA function which can produce an error could look like this.
\n\n\n\nCreating errors becomes easy, clear, and descriptive. It’s even\nstatically-typed, so the compiler will require you to construct the error\ncorrectly.
\n\nConsuming errors is simple, as well. You could use a switch statement to handle\nsome—or all—cases.
\n\n\n\nOften you just want a textual description of the error. You might want to put\nthe text into an alert view, or you might want to log out the error description\nwhile debugging. This can be handled by having your error type implement\nthe Printable protocol.
\n\n\n\nPrinting the error then becomes as simple as this.
\n\n\n\nIn my time with this style of error, I believe they are far easier to construct\nand consume than NSError, so I quite like them.
\n\nUnfortunately, Swift enums can’t export to Objective-C. So what if you want to\nuse these awesome enum errors in Swift, but still need your code to be\nconsumable from Objective-C? In that case, you need to provide a way to \ntranslate the enum error to an NSError object, and then export the NSError\nobject to Objective-C.
\n\nYou can pull this off by adding a foundationError property to your enum error.
\n\n\n\nThen, in code that can return an error, you must provide overloads that return\nan NSError.
\n\n\n\nThe NSError-returning overload will be the only version made available to\nObjective-C, so it’ll be as if your enum error code doesn’t even exist there.
\n\nSince both overloads will be visible from Swift, however, you’ll need to be\nexplicit about the overload you call, instead of letting Swift infer the type.
\n\n\n\nIt’s not the best solution, since you have to add extra code to handle codes\nand domains to the error enum, and you have to use explicit typing when calling\nfrom Swift, but it still more or less gets you the best of both worlds.
\n\nOf course, the better long-term solution to this problem is to stop using\nObjective-C altogether and just use Swift full-time :D
\n", "date_published" : "2014-12-16T13:01:52-08:00" }, { "id" : "99c1926e-2f03-4065-9a9f-21a7dce7643e", "url" : "https://donaldhays.com/2014/10/30/embedded-frameworks-in-ios-8/", "title" : "Benefits of Swift Embedded Frameworks in iOS 8", "content_html" : "Since WWDC, I’ve spent a lot of time playing with Swift.\nI’ve even shipped two apps written in the language:\nEventBoard IT\nat work and Maidenhead Converter on my own\ntime.
\n\nOverall, I quite like the language, but it’s clearly in an early state. I would\nlike to talk about Swift in greater detail later, but for now I want to focus\non one particular issue I’ve had that I only just recently conquered, and some\nsurprising additional benefits that the solution provided.
\n\nThe Swift compiler is slow. On my MacBook Pro, every 100 lines of code\nadds a full second to the compile time. EventBoard IT weighs in at about 4,000\nlines of code, and takes 42 seconds to compile. When the same machine can\ncompile a 30,000 line Objective-C app in a fraction of the time, that’s\nunacceptably slow. My much faster iMac compiles EventBoard IT in a third the\ntime, which is better, but still too slow.
\n\nThis one issue was leading me to postpone doing further significant work in the\nlanguage, which saddened me. I tried numerous suggestions to improve\ncompile times—explicitly type everything instead of taking advantage of\nthe implicit typing feature, watch the build log to see if any one file was\ntaking a disproportionately long time, etc—but nothing seemed to make a\ndifference.
\n\nWhile the compiler needs to speed up generally, one of the biggest\nproblems it has right now is that it doesn’t delta compile; every time you hit\nbuild it will recompile the entire app, and not just the parts that changed\nsince the last build.
\n\nThe Swift team explained that this is because of the nature of the language.\nIn Objective-C you have explicit #include
statements that make it really easy\nto build a dependency graph, which makes it possible to see which parts of an\napp might be affected by a change in one source file. Swift doesn’t have that:\nany source file in a target can see any symbol in any other source file in the\nsame target. Because of that, the compiler can’t easily judge which files might\nbe affected by a change in another file. The Swift team has said they intend to\nimplement dependency analysis in the same way the C#\nteam does, but that doesn’t exist yet, so your entire app recompiles every\nbuild.
As it turns out, there’s a way you can take advantage of delta compiles in Swift\ntoday: embedded frameworks. While the compiler can’t do dependency analysis\ninside a target, it can do it between targets. If the code in an\nembedded framework didn’t change since a previous compile, it doesn’t need to be\nrecompiled.
\n\nA few days ago I started pushing parts of EventBoard IT out into embedded\nframeworks. I’m not done with the process yet, but I’ve already cut the compile\ntime nearly in half: a delta compile takes 24 seconds. Interestingly, a full\ncompile only takes 30 seconds now. I suspect that’s because of a combinatorial\nexplosion effect, where every file you add to your project adds to the compile\ntime of every other file in your project. Since the project is being split into\ndifferent modules, each module has less to consider than the app as a whole did.
\n\nThis fix makes me excited to use Swift today again. But as it turns out,\nthat’s not the end of the benefits that embedded frameworks yield.
\n\nHeader files in languages like Objective-C have one really distinct advantage:\nyou can declare and document your public interface in the header file, while\nhiding all of the implementation in the implementation file. When done well,\nyou can look at a header file to learn how to use a class,\nwithout ever having to look at the implementation. Modern languages don’t have\nheader files, and so everything goes in the implementation file. This is\nunfortunate, but not so unfortunate that I think header files have any place\nin a modern language. Swift made the right decision ditching them.
\n\nBut wouldn’t it be nice if you still had a view in Xcode that just showed you\nthe public interface of your code, with its documentation comments? You get this\nview when you inspect symbols on any built-in framework like UIKit, but what\nabout your own code?
\n\nEmbedded frameworks give you this public header view. In source files that use\nyour framework, you include an import
statement. If you command-click the\nframework name in the import
statement, you will see the public header view.\nIt shows the documentation comments you wrote and the public symbol\ndeclarations, but not your private nor internal symbols, and not the \nimplementations of your public symbols. It’s glorious.
When you write a view controller, you often write various sub-controllers or\nviews or model objects that are used by the view controller, but not by anything\nelse in the app. Your classes might also have public properties and methods\nthat are used by these near-neighbor classes, but are not relevant to the rest\nof the app. Unfortunately, even though these classes are only used by the one\nview controller, their symbols are visible to the rest of the app. Which means\nthat anything else in your app could instantiate or manipulate them.
\n\nIn my experience, one of the best ways to improve robustness in your software is\nto limit the scope your code has visibility of at any given moment. Minimize\nglobal variables, use const
wherever you can, etc. The fewer moving parts your\ncode has access to at any given point, the fewer moving parts it can potentially\nbreak or depend on in brittle ways.
Classes are, in a sense, themselves global variables. NSObject
can be thought\nof as a global variable that refers to an object that can be used to construct\ninstances of NSObject
. Every class you declare adds another\nobject-constructing global variable to the scope of the rest of your app. A bit\nunnerving to think of it that way, no? But what can you do? Either hide all of\nyour view controller’s related classes in the same implementation file, or\naccept that you’re exposing those symbols to the rest of your app. It’s\nworkable, but it kind of sucks.
Swift’s access control support combined with embedded frameworks improves this\nsituation. By default, symbols in a Swift framework are internal
, which means\nthey can be seen by anything within the target, but nothing outside it. In an\nembedded framework, you have to explicitly annotate symbols with public
to\nmake them visible outside the target. So you can make a view controller with a\nhost of utility classes and only annotate the view controller itself as\npublic
, and then the rest of your classes have no visibility to the rest of\nthe app. Boom, those classes are no longer global variables—at least, not\noutside their framework.
A related benefit: you’re forced to think more explicitly about exactly which\nsymbols should be public. You ask yourself if something really needs to be\npublic, or which module something really belongs in. It helps push you towards\nclean interfaces.
\n\nIt feels like these new embedded frameworks in iOS 8 are going to result in a\nsignificant change in the way I build apps. I’m going to try to continually silo\nthings off in their own framework wherever I can. The compile time complaint\nwill (hopefully) go away with improvements to the compiler, but the public\nheader view and especially the improved ability to limit scope are really\nsubstantial benefits.
\n", "date_published" : "2014-10-30T17:46:35-07:00" }, { "id" : "53155576-06bb-4709-ad20-b3bdfe18e486", "url" : "https://donaldhays.com/2014/09/30/maidenhead-converter-20/", "title" : "Maidenhead Converter 2.0", "content_html" : "Tonight, I’m bringing Maidenhead Converter back to\nthe App Store.
\n\nI pulled all my apps off the App Store some time ago (was it last year? Or\nthe year before? I forget.) I would like to start getting improved versions of\nthem back up on the store, beginning with Maidenhead Converter.
\n\n2.0 is a complete rewrite and redesign of the app. A lot has changed since 2009,\nincluding a new OS design in iOS 7 and new 4, 4.7, and 5.5 inch iPhones. Also\nthe iPad happened, but I’m not quite optimizing for that just yet.
\n\nI had a number of feature requests for the original app that I never\nimplemented. Folks wanted different coordinate formats—added!—a map\nin the app—added!—and the ability to get the heading between two points—not\nadded yet, but give me time! I would also like to add features like a Maidenhead\ngrid overlay on top of the app.
\n\nTechnologically, I wanted to experiment with Swift and Storyboards. I’ve also\nused Swift in a larger app for work, and I would like to write my thoughts on\nthe language in detail later. Long story short: I like it, but the compiler is\nreally not ready for prime time yet. Storyboards worked out fine, but it was a\nsmall app and I’m not yet entirely sold on the idea of using Storyboards with a\nlarge app. Maybe if you split into multiple Storyboards. I need to think on it\nand experiment more.
\n\nWhen Maidenhead Converter was a paid app, it never made much money. After I set\nit free, it got plenty of downloads, but obviously stopped making money. This\ntime around I’ve decided to experiment with iAd. The app now shows banner ads\non the main screen. If you dislike the ads, you can purchase a $1.99 ad disabler\nto turn them off. I don’t expect to make any serious money on the app, but maybe\nit’ll earn enough for some nice food every now and then.
\n\nMaidenhead Converter 2.0 requires iOS 8. Download\nit\nnow!
\n", "date_published" : "2014-09-30T14:33:28-07:00" }, { "id" : "bbd0543c-151f-4ce1-92b9-af2f9e406265", "url" : "https://donaldhays.com/2014/09/14/4-years-5-months-4-days/", "title" : "4 Years, 5 Months, 4 Days", "content_html" : "On April 10, 2010, I put my site into a dormant state. I haven’t written a blog\npost since.
\n\nEvery few months, I would try rewriting my site, but then lose interest and put\nthe project down again. The last live version of my site was written in\nPHP and hosted on GoDaddy. My first\nrewrites were in PHP on WebFaction (which I\nrecommend over GoDaddy). Then I experimented with Node.js\n(which I recommend over PHP) on Azure. Now\nfinally, what you see is a static site generated by\nJekyll and hosted on\nGitHub Pages.
\n\nThe workflow for writing posts in this new setup is more command-line and\ngit-commit centered than I would prefer, but it does come with the advantage\nthat I can add new CSS and images and whatever else I need in the same commit,\nand have it all go live at the same time. I also frequently use my personal site\nto host little experimental prototype projects, and getting those online will be\neasier now.
\n\nThere’s been much I’ve wanted to write about. I’ve been\ntweeting about\nSwift an awful lot, but blog posts are a\nmuch better place to show code than PNGs. I’ve also long wanted to write about\nmy approach to app architecture on iOS. On occasion I buy new hardware and want\nto write a review about it. Now I can.
\n\nSo, I’m back, and hopefully my next post won’t take four years.
\n", "date_published" : "2014-09-14T03:26:51-07:00" } ] }