The SwiftRex project is similar to ReSwift in design: it’s a library to design applications with a unidirectional data flow underpinning. In contrast to ReSwift, which is around for years and years already, SwiftRex has had a fresh start and supports Combine, RxSwift, and ReactiveSwift to create state change subscriptions. That’s a nice touch. I’ll have to experiment with the library some day, but so far it looks nice and the README is full of sexy ASCII diagrams.
At my work at university, I was often a facilitator for groups in workshops to produce unique insights and interesting visualizations. We experimented with a lot of things – one particularly successful idea was pair-programming, but for presentation-making. Not every pair thrived, but all pairs found out something new in the process. So I’m – well, not “on the hunt”, more like: passively fishing for new ideas like this all the time.
Just this week I came across Nielsen Norman Group’s newsletter edition about sketching of diagrams, user interfaces, and stuff like that: “How to Get Stakeholders to Sketch: A Magic Formula”. Their formula boils down to 4 key components to encourage non-artists to participate, reduce their averse feelings, and create visualizations:
Use fat markers: thick strokes look more sketchy than thin lines, so they’ll think about the general picture more;
Tiny spaces: folded paper or note cards can help to overcome the fear of the blank paper;
Time Limits that are enforced by the facilitator can help to encourage high quantity output.
Ugly Examples that are very lo-fi encourage participants to draw ugly stuff as well
There’s no real magic involved, but this is useful advise to keep in mind when you prepare the next brainstorming session or meeting.
Microsoft is becoming more and more relevant for Apple platform devs. Microsoft’s App Center swallowed HockeyApp and now the GitHub repository of the underlying PLCrashReporter framework has migrated to @microsoft on GitHub. They have now just released v1.4.0, so it looks like the future of Open Source crash reporting is bright for a while.
Since I’m spending so much time in Apple Keynote anyway, I figured I might as well share a couple of tricks. Here’s one. When you use the “Spin” animation for showing an object, it usually spins around the center. That works well when you have rectangles or square diamonds. With rotated shape objects, I was less lucky.
I really want to like Swift property wrappers for UserDefaults. But I have a hard time making them 100% useful. Take the post by Andy Ibanez on the topic for example. It’s a well-written post with great code examples. If you want copy-able code for your app, read it. It’s good.
I don’t show a clock on my computer. Sometimes, I quickly want to find out what time it is, though. I often run date from the shell to get the current time, and can often get there in my Quake console-like iTerm 2 Hotkey Window by pressing the “up” key since I seldom use the Hotkey Window for anything else.
The situation was resolved, but it took 1/4 of a year for Guilherme and Apple to resolve the issue. Read Guilherme’s post about the incident.
I don’t want to blame Apple here. I just want to make sure that we all stay aware of the fact that part of our livelihood depends on a company than can, and will, make mistakes eventually. These mistakes can become fatal for your business.
If you do a simple exercise in Antifragility1 training, you’ll see that having all your eggs in one basket where you do neither own the basket, nor the eggs, puts you in a pretty bad situation.
This is an affiliate link. I get a small kickback from any purchase from amazon.com without any additional cost to you. ↩
Today I learned about an ingenious tool called csplit on the Zettelkasten Forums. It’s available on macOS and Linux. You can use it to split a single Markdown file into multiple files, one for each chapter or section.
I use Dash every day. And while it seemed the last upgrade to v4 wasn’t that long ago, my 1Password-powered licence purchase history tells me it was in February 2017 that I last paid for a Dash license, almost 3 years ago. So it’s about time that a paid upgrade hits Kapeli’s online store!
Emacs is a text editor, kind of. But I use its Org mode for “keeping notes, maintaining TODO lists, planning projects, and authoring documents with a fast and effective plain-text system” – its Agenda became my daily productivity hub. It’s a calendar view of all things scheduled for the day, plus some other info interspersed: thanks to the plain text nature of the whole interface, it’s simple (albeit not easy) to re-style everything you see there. Add sub-headings, spacing, links, text, what have you.
I was recently following a link to The Wiki, the original c2.com wiki by Cunningham & Cunningham, Inc. It was a link to the FourLayerArchitecture page. At the very bottom, it currently says “Last edit August 25, 2006”. In the early 2000s, the wiki had to be closed for editing by the general public because of abuse, and this page seemingly lays dormant ever since.
A very strange obstacle to overcome when you just get started with iOS or macOS programming is to use custom views or view controllers. How does this magic even work? And what do the steps mean that you have to perform? When you use a Xcode template, you get a Storyboard or a Xib with the most important components for an initial, empty app to display something on screen. This is accompanied by an AppDelegate and a custom ViewController class. If you don’t know anything and just get started developing for iOS, say, then this is a good place to start hacking away: after all, the bare-bones infrastructure has been handled for you.
I don’t know why this Black Friday thing exists, but I figured I could participate this year to see what happens on this day of frenzy. So here you go, everything on this website is 50% off on Friday (+/- a couple of hours to accommodate other timezones). See also:
For about two weeks now, I’m almost exclusively working on the upcoming Zettelkasten Online Course, providing text feedback on the script and creating presentation slides. I’m picking up speed as early style decisions are settled, but there’s still a ton of stuff to do.
The WordCounter update to v1.6 is online! It brings the long-awaited statistics module so you can get an overview of your productivity over any period of time. It also comes with a CSV export of the visible data. Download the free update! Export and the aggregate numbers will be expanded in future updates. The stats currently supplement the daily calendar history, but the history will be obsoleted as I move the daily details into the analytics part itself.
Working on a greenfield project is nice, but it also brings up all the uncertainties of the start: which components, modules, objects, interfaces do you need? With Swift, you even have to decide if you want to design the system in an object-oriented or a functional way. As far as the core functionality is concerned, you do have this choice. (When it comes to UIKit/AppKit, you don’t.)
With some luck, all my Windows programming wet dream might actually come true one day. There’s progress on making Swift available on Windows, and there’s progress on providing a Win32 API wrapper for Swift so you can share model code across platforms and write UI for Windows and Mac separately.
Berlin-based company ExactCODE, makers of ExactScan and OCRKit, experiences trouble with Catalina and a rather short time to submit bug fixes for their app before the public release of Catalina earlier this month. They decided to leave the Mac App Store behind:
each manual update review by Apple causes delay and drama
AppStore does not support paid upgrades, only new App, in-App purchase or subscriptions
Apple takes 30% and that is not sustainable to run a company and pay salleries
it is not provide to provide free updates forever
if you purchased our application this year we provide a direct license, if you had it significantly longer, we think a paid upgrade is fair for continuously developing, improvements, and support
[…]
There is mostly only one benefit [of using the MAS] for users: one central place for purchasee and updates. However, there are many negatives, such as: […]
I don’t know if they could’ve done more to prepare for the macOS upgrade. Recently, folks on Slack shared screenshots, and it turns out that as a serious Mac developer you apparently have external hard drives full of previous and future macOS versions, plus a stack of different Xcode versions (that are no longer available for download by Apple!) – that’s required by virtually everyone in order to support multiple OS versions and fix bugs. The Catalina beta also was very flaky.
After releasing the Catalina Golden Master build to developers on October the 3rd, we immediately finished fixing any new crash or issue we could find over the weekend. In our opinion, leaving developer just four (4!) days over a weekend with a public release on October the 7th is not very helpful nor professional.
They have a point here. But could they have fixed the same bugs earlier in preparation of the Golden Master release?
The call for App Store submissions went live on October 3rd, too, at the day of the Golden Master release. So even if they fixed all the bugs early, Apple would have had only 4 days to review all App Store submissions, which sounds like a bad idea nevertheless.
Shameless plug: I also wrote a book on selling outside the Mac App Store in case you want to leave the App Store, too, or make your company more resilient through availability in multiple stores.
After a couple weeks of experimentation, I find that twice weekly email delivery of my recent blog posts is one too many. I wrote a lot in the past months, so each issue contained quite a few links. But who wants more email with less links in it? I don’t, so I changed the interval to weekly, delivered every Thursday, covering a summary of the whole past week.
As an exercise, I wrote a simple iOS scene transition from a login form (root view controller) to a success scene. I was experimenting with the Model-View-Presenter approach where view and presenter know each other, but communicate through protocols, so you program to an interface, not the implementation. I ended up using a simple state machine to represent the view’s state, and employed form validation that is represented in the types. I like how the result reads, so here’s a rundown of the exercise:
What I called an Xcode bug last week turned out to be a broken project configuration that was absolutely my fault. Back when Hardened Runtime was introduced, I switched it on at the Xcode project level, not just for the app target. When you set “Enable Hardened Runtime” on the project level, all targets inherit this setting: the app, the unit tests, and the UI tests. With Xcode 11, it now turns out that hardening the runtime for the test runner broke an internal library lookup in perfect accordance with the utility of the Hardened Runtime settings.
Rich Siegel recently wondered on Slack why NSTextView would suddenly display empty placeholders for some glyphs when the font does not support them, instead of falling back to a safe font like it usually does. Chinese characters never got displayed. Michel Fortin remembered a similar problem, and the potential fix was quite simple:
In summary, if you have to change the font after the text storage was edited, do it in willProcessEditing and it’ll do the right thing. Don’t do it in didProcessEditing.
That turned out to be what tripped up Mr Siegel’s text view, which now happily displays CJK/CJKV again. For more details and some background about how you can detect this problem in your apps, read Michel’s post.
I’m currently revising code from 3 years ago. The result is a replica of the old stuff – updating isn’t worth the effort, it’s written in Swift 3 and the code base is small, so I rewrite it and copy useful parts over. The public interface already differs from what I wrote 3 years ago. In the first step, I translated the old code but took what was there. For example, back then I had a DateRange type. Swift Ranges were less powerful back then, so I added a couple of convenient methods that I can now replace with the standard library protocols instead. So I demoted the type to typealias DateRange = Range<Date>. I also had a Date type (this was before NSDate dropped the “NS”) that I renamed to NormalizedDate. In the domain I work on, a date isn’t a date-time-combination, but just the year, month, and day. Confusingly, this type was a mere wrapper for NSDate that dropped the time information for quick comparisons.
By accident I found a setting for emacs windows that prevents a window from displaying any other content than what it currently is showing. It is not locking the textual contents but the buffer. That means you cannot show the contents of another file, or change the currently visible help page, or whatever.
Emacs can display interactive help windows (the content/buffer name is called “*Apropos*”), and compilation results. I managed to limit the height of the compilation window to 10 lines already. But when I have the compilation results pane focused, I want to close and dismiss it quickly.
The project that I’ve been working on over the weekend, I worked on in emacs. This is part of my re-learning the basics of text editing and programming in emacs to slowly move away from TextMate when it comes to scripts. I want to move away from TextMate because I eventually want to transition to be productive on a Linux machine – that means, to create stuff in an otherwise foreign operating system. Emacs is portable, so that’s a good start.
This announcement is a very difficult one: I cannot work on The Archive for the next week or two, maybe, more. That’s because with Xcode 11 and Swift 5.1, UI Tests stopped to work. Like, at all. I have created a Feedback ticket (FB7338237) and now also have a Technical Support incident open, awaiting a reply by Apple engineers to help with this.
I was experimenting with PHP development over the weekend to whip up a properly unit-tested library to generate license codes, hosted on your own web server. I wanted to make use of my newfound emacs prowess and figure out how programming is supposed to work with the stuff I have and have not prepared so far.
Since macOS10.15 Catalina, you cannot easily make public logging the default anymore. os_log hides contents from string interpolation by replacing the string with <private>, unless you explicitly annotate the value with %{public}. That’s probably supposed to force developers to think which parts absolutely need to be part of the log and thus reduce accidental logging of private information. Saagar Jha shows how you can enable your dev machine to log everything again.
For all throughout human history, you had to symbolicate your user’s crash logs using atos or a 3rd party tool to get human-readable output. Otherwise, you will not know the symbol or method name of your app’s parts that are involved and see memory offsets instead. But with Xcode 11, double-clicking a .crash file now opens Xcode instead of Console, and you can view the crash log in the context of a project. That’s very nice.
I uploaded another episode of the video series where I document how someone might process reading notes from a book after reading it. I don’t have any Range related project, so here I’m just processing the book from start to finish instead of looking for anything in particular.
This episode is shorter, because I didn’t find many useful ideas in Chapter 3. And the ideas I did find interesting were not citable, so I had to look the originals up. That took most of the time, but did ultimately not produce many new notes. It’s interesting that after a couple of session I already begin to form an opinion of the quality of Epstein’s research. There’s lots of endnotes, but the quality is … well, enjoy this episode to find out more!
I’ve just published an overhaul to the website that affects all the CSS. I do hope the typography looks better in general. Also, I’ve revamped the books and apps pages to look nicer, have more detail, and make purchases easier.
The large update and rewrite of “Make Money Outside the Mac App Store” is finished. I have published an update of the book to Leanpub edition and the one you can get directly from my website. The print edition is still work-in-progress, but I should have something available later this month.
The following I decided to cut from the update to my book, Make Money Outside the Mac App Store. I came up with a list of arguments that you can apply to your business model and app if you haven’t decided if you want to embrace or ditch the Mac App Store.
Yesterday, Oliver Böhm and I have conducted our Code Retreat Workshop at Macoun 2019. Opposed to the passed-down spirit of Code Retreats, where throwing your code away at the end of each session, our workshop’s participants often wanted to see how the other teams attempted to solve the problem at hand. So we decided to prepare a public GitHub repository. As of now, there’s nothing to see, but I’m curious to find out if the functional programming language tag team will upload their OCAML- and Scheme-based implementations, and which names all the other folks have chosen during the sessions where they had to write tests first.
While I was working on the update of my book, Make Money Outside the Mac App Store, I compiled a comparison of popular e-commerce solutions. My first test reader Sascha found this to be distracting from the books technical objective, so I cut it out.
Another episode went live today – earlier than the last weeks, because I’ll be travelling to Frankfurt for the Macoun conference from Thursday to Sunday.
This chapter was harder to process. There seemed to be parts missing in the story. Maybe I’m too sloppy and haven’t noticed the missing pieces? Either way, something’s amiss in Range land. I also notice that the topics from chapter 1 were connected to the topics here somehow, but it’s just a hunch how things will fit together eventually. I’m looking forward to the next episodes, because I hope it “clicks” and I know how to split the sequence of notes in the structure note up into new Zettel notes and then work with the more powerful web of notes instead of this monolithic book overview.
The build tools have changed a bit with the release of the programming environment Xcode 11, and I figured this might just be as good a time as any to publish small compatibility updates in preparation for macOS Catalina and to support iOS 13. So I released updates to nearly all my apps in the past 7 days:
This blog post was originally meant as a reply to the ReSwift issue “Any way to control the priority of subscription callbacks?” – If you find asking yourself this question, this should help. This implementation detail is hidden by design. If you find yourself wanting to affect the order of subscription callbacks, there’s a concept of a sequence waiting to be extracted somehow. Or, the other way around: if you want to affect the order, your design is wonky.
I uploaded episode two of the book processing video series on David Epstein’s book Range:
In this episode, I process the few highlights from Chapter 1. I end up with many more links than last time already. I also employ the method of creating a forward-link, i.e. adding a link to a note that does not exist but that I need at a certain location in my structure note, then add the details. The upside: you already have 1 connection!
The devs of Little Snitch came up with a convention to annotate network traffic, so to speak. It’s called “Internet Access Policy” and will show the purpose of your app establishing a connection in Little Snitch’s warning dialogs.
It is implemented by adding a InternetAccessPolicy.plist to the app bundle with a dictionary of connection details. This could potentially be used by other 3rd party firewalls as well. That’s what I like most about it: it provides useful information to end users without locking developers into anything. A Property List is innocent enough and could potentially spawn other uses.
Look at the project website to see how many of the big names have added IAP’s to their apps already, plus yours truly: Acorn, BBEdit, MindNode, Ulysses, Paw – and many others.
This reminds me of a time 10 years ago when macOS didn’t support tagging of files, yet, and the OpenMeta tagging convention was introduced by indie devs and became a roaring success with various productivity apps.
I have just released an update to my very first commercial app, Calendar Paste. It’s now v3.3.0 and sports iOS 13 compatibility, Dark Mode, and overall better layout. So it’s mostly a cosmetic and “minor tweaks” update.
Calendar Paste 1 was introduced back in late 2012. That’s 7 years ago! So, happy birthday, Calendar Paste!
To celebrate, Calendar Paste 3 will be available for free from Oct 1st until Oct 6th, and then 50% off until the end of October. The App Store listing doesn’t seem to be updated despite it being “Ready for Sale”, for whatever reason, though. Maybe it’s already fixed when you read this. v3.2 will work just fine, but not sport Dark Mode, yet.
The app was my first real app project, sufficiently simple to start with, yet interesting enough to be sold on the store.
Calendar Paste 1 kicked off my indie app developer business. I still don’t make a lot of money and have to freelance to stay afloat, but this is a very cool path to have taken. I’m loving it. In case you wonder: it never was a huge commercial success. For 7 years, it brought in something between $3 and $130 per month, with a guesstimated average of $18.53/month. Unless it didn’t sell at all, that is. So much for the dreams of yours truly in 2012 to get rich quickly, right? But I learned to code in Objective-C, use Core Data, program for iOS 5 (and then iOS 6 before the app was finished). That’s worth a lot.
That’s why I don’t sunset Calendar Paste, even though each year’s iOS update takes away time for maintenance. And I cannot warrant to add all the planned features to the app because the time is better spent on other, larger projects.
I also wrote a diary of the progress, taking extensive notes in a tutorial-like fashion, that I eventually wanted to publish as a $5 ebook – but I never did. It just didn’t seem to be worth the trouble, and shortly after most of the code was already outdated, and the lessons learned not easily applicable to Swift.
Sorry if you’re still waiting for iCloud sync. It’s theroetically possible, but would take about a week or two to implement and test, and that’s just too costly at the moment. One day I’d like to out-source development of features like this, but to do that I’d need to accumulate larger savings – so either me or someone else working on the app depends on the same solution and y’all have to hold out a bit longer.
When you want to merge newsletters in MailChimp like I do and tell your subscribers to sign up at the new list and unsubscribe from the old to not receive any notifications – then you’re setting yourself up for trouble! Because it turns out that mass-migrations from list A to list B mostly register as mass unsubscribes from list A. And an unsubscribe rate of 9% or higher (I don’t know the actual minimum value, but 9.23% triggered it for my account) will automatically up the risk level of your whole MailChimp account.
When someone close to the family dies, a lot of dust is stirred up. My godfather died last week, and I was informed that his burial will be tomorrow – more by accident than by plan. We hadn’t talked in 5 years, and in late 2018 I became curious what he and his wife were up to. Why not visit them for a change, since they don’t come visit anymore? I was at their place a couple times, but most of the time, like once every month plus for birthdays or so, my godfather and his wife visited us at home, back when I lived with my father.
For the Zettelkasten knowledge project, I’ve recorded and cut my first video. The process was a pain, and I think I’m going to write about it later – but for now, I’m happy with the result and very proud to have finished this mini project.
It’s part of an ongoing series to demonstrate the method we talk about on our blog. Here’s the video:
Comments are very, very welcome. So head over to the forums and tell us what you think of it!
My ebook update routine has changed a bit for Swift 5 this year: I’ve expanded the “Make Money Outside the Mac App Store” book typoscript a lot. It’s about twice as long, with many more explanations for the setup, many new additional feature discussions, and practices that I’ve learned of in the last years. FastSpring’s revamped store kind of forced me to re-take screenshots anyway, so I figured I might as well take more.
Not everybody knows how to consume RSS, so I wanted to try to make updates to the blog available via email. That’s why I have now revived the newsletter signup page. This is the plan: I’ll experiment with this setup for a while, but I think the current options cover almost anything I currently do, or plan to do, so that both developers and customers of my apps get something interesting in their mailboxes.
The TextMate auto-updater surprised me yesterday by installing v2.0. No RC suffix anymore, just the plain number. That doesn’t mean this update comes with any crucial feature. It’s just a message of intent: this editor is worthy to be a successor to TextMate 1.
2019 is a weird year for developer platforms. Microsoft App Center will incorporate HockeyApp. HockeyApp is discontinued in November 2019. The App Center will be supporting Sparkle feeds in the future, too. So Microsoft will offer a service that may be useful to deploy macOS apps, soon?
In my post about redirecting the DevMate update feed, I missed the opportunity to mention that you should probably also update your app very soon to not rely on DevMate’s framework.
Mr Boy van Amstel at Danger Cove picked up the topic and explains how you can change your feed URL inside the app using the Sparkle SUUpdaterDelegate methods. DevMate’s closed-source framework wraps this in its DM_SUUpdaterDelegate_DevMateInteraction protocol.
Your battle plan thus should be:
Redirect the remote feed URL to deploy updates to existing customers working with old versions, and
Change the feed URL used inside the app as soon as possible and deploy an update to not rely on the redirect for too long.
I use the SUUpdaterDelegate to switch feed URL’s in The Archive and WordCounter, too, in case you wonder if this is a good idea in the first place.
Fellow developer Daniel Kennett mentioned that he requested a HTTP redirect for the DevMate feed to his own server. I probably wouldn’t have thought of this, and think it’s a great idea. This way, you can reach DevMate customers long after their servers have stopped responding.
My favorite monospace programming font, Fira Code, was updated to v2. This is even supposed to solve an issue with regard to line height inconsistencie with bold fonts that the Fira Mono team decided not to fix. (Darnit!)
Fira Code is fun. I like the operator ligatures for e.g. != the most. Good stuff.
I’ll be at this year’s Macoun developer conference in Frankfurt (Main) again. This time, I’m not giving a tech talk, but hosting a workshop with Oliver Böhm. The Macoun is a German conference, and it isn’t expensive. I think that’s a great combo. You should go if you can. The community, or family, built around the conference over the past dozen years is very, very welcoming. You cannot not learn something when you attend.
Server-side app license code validation, as I imagine it, in a nutshell: If the token expires and there’s no server connection, you have to figure out how punishing you want to be. I suggest you do not punish by default and assume people have good intentions. Possible escalations: Remote or server-side deactivation of licenses can be useful to prevent continued use after refunds.
Seth Godin points out that people usually say “an acquired taste” as if that is something bad. I never thought about this phrase much, but he does have a point here. Indie developers and creators in general should consider to be a pleasure for the introduces few: that thought is in line with getting your first 1000 true fans, and everything the crew at Basecamp (formerly 37 Signals) around Jason Fried preach for years. Retain your individuality. Make something that is indispensible for people instead of making a throwaway mass product.
Noah Gilmore wrote about his approach to use UINavigationController inside a popover without subclassing the navigation controller. Even though I don’t work on iOS apps, like, at all these days, this sounds too useful to go by unnoticed.
Hopefully this was a helpful look into the world of preferredContentSize, view controller wrapping, and UIKit popovers. Here’s a tl;dr:
To define the size of your popover with autolayout, set preferredContentSize to the result of systemLayoutSizeFitting
To animate popover size updates at the same time as navigation controller animations, wrap your UINavigationController in a PopoverPushController (see code below)
When you change your controller’s preferredContentSize, be sure to change the preferredContentSize of your controller’s popoverPresentationController’s presentedViewController as well
DevMate are closing their doors. The announcement isn’t news anymore, but since I didn’t use their service, I didn’t think much of it. I did report back in 2016 when they changed their pricing model. Nowadays I discover more and more people struggling to migrate away, and my blog pops up in their searches – apparently because I wrote a book on selling apps on FastSpring.
We’re using a Vanilla Forum for the Zettelkasten Method and ME Improved. It’s a PHP-based forum, and I like how modular it’s built. Writing plugins and themes isn’t a pain, and that’s something in my book already. It also allows us to power the comments with the forum. When you are the first to write a comment, the built-in “System” user creates a discussion with the blog post’s title and a short excerpt and your comment is added.
Daniel Jalkut of MarsEdit fame released a little Swift helper to detect when a macOS app has been moved during runtime. His write-up explains everything. In short, moving an .app bundle while the app is running will inevitable result in resources not being found, and occasional also in crashes.
This or a similar helper is a practical necessity in all applications that are distributed outside the Mac App Store.
The long defunct LetsMove used to be a tool that tried to prevent the issue by offering to move the app to /Applications upon launch from any other directory.
I discovered the FastSpring Examples page the other day. There, you can interact with different store setups to get a feeling for the capabilities of FastSpring’s new and updates Store Builder API. The examples also either include or link to documentation pages and CodePen-like source code demos.
All in all, I think this is a very cool addition to the docs.
When you play around with the examples, you will see that the new store styles aren’t just for fancier checkout pages. The new store has an API that you can easily (!) use to transform even a static HTML website into a dynamic store front, including a live shopping cart. This is very, very powerful.
Last December, my grand-father died. His breathing got shallow, he wasn’t hungry all of a sudden, then went to take a nap in his favorite chair. There, he slowly, and I hope painlessly, began to tune out a bit, fall asleep, and eventually cease to … live. In the days after his death, I helped a bit with the funeral preparations, and I take care of my nearly blind grand-mother once a week ever since. I spent a lot of time with my grand-parents. We were pretty close. I love them, and so I begin to crave for some kind of totem that keeps a piece of my grand-father’s live somewhere visibly in my life.
I am currently editing a new version of my ebooks to update them to the latest Swift and include new features. Writing prose instead of code for the better part of the week took some getting used to, but I really enjoy the change of pace. Especially now that my flat-mate got a 1-year-old dog that has to be guided about what it means to be living under a roof with both of us.
This is a pretty huge update. It introduces native macOS multi-tabbing to The Archive – which means you can now open multiple tabs or windows and have different search contexts active. We call these contexts “Workspaces”. On macOS10.12 and newer, you’ll get native tabbing of windows; for macOS10.11 and earlier you’ll get multiple windows only.
Did you ever want to re-create the macOS Main Menu in HTML to show stuff related to your app? It’s hard for me to accept that anyone would ever build this, but Brett Terpstra did.
Check out the live HTML demo. This is so weird! It’s like you’re running a Mac desktop in your browser.
If you write documentation for your app that includes menus, and you want to automate the process, taking into account the ever-changing nature of an app’s menu during development, niftymenu might be just your thing! The menu can be grabbed from any app, and it comes with, well, nifty features for taking screenshots.
I noticed this when experimenting with multiple tabs. When you set NSWindow.title to an empty String "", the window/tab will be hidden from the window list in the submenu below the “Window” main menu’s item. I expected a menu item with an empty label, but instead you get no item at all.
I found an interesting connection between two articles about paid up front apps, and how this paywall can work to your advantage in two ways by separating the ap user’s population into two groups, prospects and paying custoemrs: I never thought about the effect of paywalls on support email volume until Jordan Morgan launched his app Spend Stack the other day and now published an interesting argument pro paid up front pricing. Paid up front will limit your user base a lot compared to free-to-download/freemium, that’s true, but you’ll have a far lower volume of support emails, and you will only get emails from paying customers. Jordan receives 10–15 emails/day at 500 downloads/day right after launch. If you think freemium will increase downloads tenfold to 5000/day, he would also have to deal with hundreds of emails!
Found a question about how to “best” write the tests for the Fizz Buzz kata. The author provides his approach and questions as a GitHub Gist. One interesting takeaway is his use of the name of his constants, e.g. anyNumberDivisibleBy3 = 3. It expresses very well what kind of placeholder this number is supposed to be.
After the fiasco of sharing a single NSWindowController among multiple NSWindow instances, one per tab, let’s look at a proper implementation. For the working example, see the code on GitHub.
This is a follow-up to “Programmatically Add Tabs to NSWindows without NSDocument” from January this year. There, I was creating NSWindow instances from storyboards and re-used a single window controller to manage them. The point of that post was to solve the problem that newly created tabs will themselves not respond to the “+” button – or any menu action, for that matter, because they fell out of the responder chain at first.
I almost never forget to pack stuff for my regular trips to the gym, family visits, or shopping. Of course I sometimes do forget to pack something for a weekend trip, or I overpack books when I visit friends over the weekend and am afraid to run out of reading material during the train ride. But for the daily leaves of my appartment, I do not forget to pack keys, phone, money, writing utensils, sketchbook, etc.
I don’t know when was the last time I received a Microsoft Word .docx file. However long the streak may have been: it has been broken today. The document contained links and embedded images. I was instantly taken aback by the prospect of all the manual labor of extracting the images and saving them to files, not even knowing how MS Word behaves nowadays.
The past couple of days, I’ve been working on integration of an automatic crash reporter. Turns out that on some machines The Archive is crashing regularly during search, and I want to track this down. I need data by more than the most courageous users who can venture into the Console to track down crash report files and send them to me.
So I bit the bullet and began work on a server script that would accept crash report files and email them to me. I think that’s better than making users email me crash reports directly. Not everyone has Mail.app set up on her Mac, after all.
Just have a look at the code: Collecting .crash files and sending them over? Sounded simple enough! NetNewsWire even sports a very humble crash reporter UI, and automatically sending reports on the user’s behalf if the user choses to do so. The required Swift types are simple enough to integrate once you figure out where Brent put all the helper extensions :)
I cannot stress enough how amazing open source is. All this experience, assembled in publicly available code repositories for everyone to grab and use. This is crazy.
I am now rolling this out for my apps, starting with the WordCounter and The Archive on their respective “beta” update branches to see how it works in practice. The Swift code is simple and I trust it doing its job. But the server script, well, it needs to be battle-tested now!
I’m going to add public-key encryption of messages and/or some sort of authentication to prevent malicious attackers from spamming me with emails that, well … I send to myself.
I just released an update to Move!, the work break app I develop and use. It fixes a couple of user experience issues, like displaying a Dock icon when you view the preferences so you don’t lose the window.
Also, the app’s preferences didn’t display license details properly on Mojave and above. The app now uses Swift 5 and updated external libraries under the hood, is properly notarized (hello, Catalina!) – and a couple of MiB larger than before. I am looking forward to when we can depend on the Swift runtime being available on user devices.
I manually edited about 400 occurences of code block markers from #!swift into \“swift`. I hope I didn’t break anything in the process. So far, things look good. If you find oddly looking posts or broken code blocks, please tell me about them. There’s no way I can find problems on my own in 10 years worth of blog posts :)
This time, I don’t want to find out if the app is compiled as debug/release mode; I want to find out if the debugger is attached. I found an Objective-C answer on StackOverflow which is based on HockeyApp-iOS.
There’s no standard shortcut to fold the current subtree of an org-mode outline. When I work in org-mode outlines, I usually am 3 or more levels deep into a so-called “subtree” and want to get back to the root item, fold it to hide the details, then drill down into another item. I use that when I am working on an app and want to have a look at a planned milestone nested deep down at a different point in the outline.
There is a free ebook out there that teaches you the basics of Combine, Apple’s reactive framework introduced at WWDC 2019. It is pretty long already, given the time author Joseph Heck (@heckj) had to learn about Combine and then write about it. From what I saw, I think it’s a good introduction to reactive programming in general.
I don’t know what’s going on this week, but I have written a lot for the blog. I also carved out an hour and a half today to update the structured overview of articles on this website. I always wanted to make it a good entry point but didn’t update it during the transition to another blog platform, then back again, and now it’s 2 years later already. Phew!
Today I noticed that I never followed up on my FastSpring webinar of 2017 called “Beyond the Mac App Store -
A Practical Guide to Go From Code to Cash” with the slides! Sorry, folks!
I’ll also upload the checklist we served attendees.
People in Slack asked me why I didn’t use another mechanism to get notified when NSWindows are shown. Here’s what I was suggested and what I found: NSWindow.didChangeScreenNotification:
Does not fire for all windows showing for the first time, and if it fires, if firest only once. Closing and re-showing the window will not trigger the notification again.
I updated my app the WordCounter for Mac to v1.5.0 today. This update includes a couple of modernizations behind the scenes, but most importantly fixes problems that were related to the app being a Dock-less menu bar app. You couldn’t manage any of its windows well. Now you can, because when any additional window is shown, a Dock icon is added on the fly.
When I pointed out that Sparkle finds its XPC services on its own, I mentioned you can see how it does this by searching for “SPUXPCServiceExists”. If you take a look at the use of this function, you’ll see something like this in the Objective-C (!) source files:
How do you observe for changes to the list of visible/known/active NSWindow instances in your app? There’s NSWindow.willCloseNotification, but there’s no equivalent like a willShowNotification or didShowNotification (except for NSPopover). I don’t know why, but I do find it strange.
In the previous post, I talked about how to download the “modern” Sparkle updater branch called ui-separation-and-xpc that allows you to update sandboxed apps and migrate your code to use the new types. This time, we’re going to use the actual XPC services that do the grunt work.
The Sparkle XPC fork is even better than I would’ve imagined! As I mentioned in the previous post about Sparkle’s XPC branch, you can switch to the new framework version and the new types without having to change much else. The new API is very similar to the old one. If you switch to the work-in-progress ui-separation-and-xpc branch, then you can continue to use CocoaPods or Carthage if all you want is the new API.
This is the first post in a series: The standard solution to provide app updates outside the Mac App Store is to use the amazing Sparkle framework. The releases of Sparkle don’t support sandboxed applications well, though, so the core maintainer Kornel Lesiński (@kornelski) is working on a more secure fork of Sparkle next to the existing one. He’s maintaining the regular Sparkle, and the fork. The fork features various XPC services to deal with Gatekeeper security configurations and Sandbox entitlements in a proper way. (I have to phrase it in such a vague way because I have no clue about the details, yet. Explanations are very welcome in the comments!)
The default Interface Builder approach of using a “Shared User Defaults Controller” object breaks down if your app preferences are not stored in the standard place. Both my apps The Archive and the Word Counter for Mac are comprised of multiple executable applications. For The Archive, it’s the main app and the Quick Entry popup window. They share some settings, like which theme and font size is used. To share these settings, I rely on NSUserDefault (or just UserDefaults in Swift now). I cannot use the UserDefaults.standard, though, because that is tied to the currently running app’s bundle ID. In the case of the main app, it’s the ID of the main app; but for the Quick Entry helper – or any helper app –, it’s the helper’s bundle ID. This way, the defaults dictionaries are not shared.
Brent Simmons wrote about imposing sanctions by making apps unavailable in certain countries (in his case: Saudi Arabia) in November 2018. I never thought about the mere possibility of doing so. It’s an intriguing thought: even when politics don’t result in whatever you want, you can always be picky about who you do custom with. It’s a power we have, a power every producer and craftsperson has. Turn down a business for moral reasons.
If you’re a student and apply for GitHub Education, you get a lot of cool stuff for free. Part of this cool stuff apparently is “aws educate” access, I was told: GitHub Student Developer Pack members receive up to $110 in bonus AWS credits for a total of $75-$150
In anticipation of macOS10.15 Catalina, I have changed my shell from bash to zsh. macOS10.15 will use zsh as the new default, and I was pretty sure that things will break immediately unless I prepare – so I did prepare, and I found the transition very simple. My old bash prompt didn’t work out of the box, so getting a decent prompt with some color and git repository information, I managed to set up sindresorhus/pure to offer asynchronous (!) info like the pwd’s git metadata.
This weekend, I released an update to the note-taking app I’m working on for a while called The Archive. This update is pretty big for people not getting updates from the opt-in “Cutting Edge” update channel, because all of a sudden the app allows you to navigate back in time. The navigation stack (what you’d call browser history available from the navigation buttons in your browser) behaves like this:
Found embetty, and now I am reconsidering to embed marked-up Tweets and YouTube videos again. Embetty displays Tweets as proper cards, but without Twitters visitor-tracking code. Instead of screenshots, they have a demo page.
Python has the with keyword that is analogous to using in C#. It is used to manage resource access and wrap a block of code with setup and cleanup stuff. I like it. Here’s an example adapted from the Python Enhancement Proposal (PEP) 343 that introduced the implementation in Python 2.6:
The music player daemon, mpd, and its client counterpart mpc operate on a managed directory structure. All paths are relative to this root directory. You cannot make mpd play a file from just anywhere, it seems. This is important to know when you script MPDClient using python-mpd2, because when you try to add any absolute path, even those pointing into the managed directory, you’ll be in trouble.
I am using Emacs for over a year now to manage my tasks. I like how I can mix tasks with long form notes in a single outline. It’s good. We had to play with vi and emacs for a while at University. I’m very happy I got used to the very basics of both editors because I ended up using vi a lot when SSH-ing into remote machines, and now Emacs for everything else.
Since I put TableFlip on the Mac App Store, I sell about 1 or 2 copies each day. I didn’t invest any time in marketing, yet, apart from the announcement post here plus a tweet. That’s why I think these sales are driven by search terms through the Mac App Store. Then again, maybe not, I cannot say.
On macOS, the field editor is a NSText instance that appears whenever you edit a NSTextField. This means the text fields themselves offer no editing features; they just tell the shared field editor to appear in their drawing area and show their content. When you write XCUITests, you may want to edit cells in a table or fill out a form with many text fields. Today I learned that you don’t get to the field editor in UI tests and send it the typeText message. You work with the text fields like the user does: as if they themselves accepted user input.
Today I work on The Archive. The focus is on an issue brought up by the community. Search results don’t update the sort order when you modify a note unless you refresh manually. In fact, the issue is expected behavior. The Archive, being a note-taking app where you can filter notes on disk with a live search, is designed to not update the search results for an active search term. Att all. This should prevent the note from disappearing from the results if you remove the search term from its contents. If you search for “foo” and get 10 results, the note you currently edit should not disappear when you cut the search term, “foo”, from it. The Archive protects the search results; a mere live-reload would change the list to 9 results, removing the currently edited one, and that’d be pretty confusing.
I also released updates to the non-Mac App Store version that fix CSV editing problems and improve the user interface. Of course both versions have the same features, so you’re not missing out on anything if you only own one version.
The app store page is a feast for the eyes. There’s a demo video (I already know how I can improve it a lot with the next update), Zebras, and lovely icy mountains.
Please share the news to help the app get traction. That would be super helpful!
I remember how weird it felt to implement this the first time. Drag & drop is actually realized via the pasteboard. So it’s more like cut and paste with a visual representation. From this you get the ability to put multiple content representations into the pasteboard at once, so the drop container can decide how to handle whatever it receives.
Since early 2019, I host downloads for my app The Archive on Amazon’s servers. The S3 bucket is a cheap-enough storage of the zip files, and the CloudFront cache is a content distribution network across the globe that improve download speeds. Here’s a long tutorial, because I will most likely forget how I did all this in a while, and chances are you don’t know how to do this either.
I was looking for an old post and found that the paginated list of blog posts didn’t quite contain all the posts I expected. Turns out I introduced an off-by-1 bug there, computing pages for 10 posts per page, but working with all_posts.each_slice(10-1), effectively dropping 1 post per page.
Of course my website isn’t unit-tested, so no wonder :)
I use beorg on iPad/iPhone to view my Emacs Org files. Until today, I did use it only for viewing files, not edit tasks, because I ran into sync conflicts. This is how I solved the problem with a few simple settings. First, put your org files into the Dropbox. I have all .org files in one directory and use the directory as org-agenda-files:
Xcode and Safari sport Touch Bar items to navigate back and forth. Have a close look: When you put two NSTouchBarItems next to each other, there usually is a gap. Between the navigation controls, there is a mere hairline divider, but not the regular fixed-width space. They are not realized via NSSegmentedControl, though. Compare the navigation buttons with the system-wide controls far to the right: volume, brightness, play/pause. (I’m listening to the 1980s Pop Radio on Apple Music at the moment, in case you’re curious.) The system controls are a NSSegmentedControl. They have rounded corners for the whole control, while the navigation buttons have rounded corners for every button. Also, the navigation buttons have the default button width.
I was removing quite a few protocols and classes lately. Turns out, I like what’s left. I relied on classes for example because they can be subclassed as mocks in tests. Protocols provide a similar flexibility. But over the last 2 years, the behavior I was testing shrunk to simple value transformations.
You can only improve things inside the frame you pick. If your frame is too narrow for the problem you try to solve, you cannot properly take everything into perspective. That’s a trivial statement as it’s only re-stating the same thing, but it’s worth stressing. Apply this to code. If you focus on code heuristics to improve your code base, you cannot improve the structure of your program. Even though the structure is manifested as code, it’s not code you should be thinking about. It’s concepts. Code is just the textual representation you stare at all day. Structure is what the imaginary entities of your invention bring forth.
While I was refactoring my app’s state recently, I noticed that there are virtually no dev logs about The Archive and how I manage state and events in this app. It’s my largest app so far, still the amount of reflection and behind-the-scenes info is pretty sparse. This post outlines my recent changes to the app’s state. It’s a retelling of the past 5 weeks or so.
Instead of writing view model types that expose the input and/or output ports as properties, consider writing free functions that are the transformation. This reminds me of Ken Scambler’s proposal to get rid of test doubles through side-effect free function composition. One of his examples, simplified, goes like this: Instead of testing what customer.pay(amount, wallet)does in your tests by mocking the wallet object, you rewrite Wallet as a value object and change pay to return the effect.
The Cocoa/AppKit documentation is very sparse when it comes to tabbing. You can make use of the native window tabbing introduced in macOS Sierra with a few simple method calls, though. Conceptually, this is what you will need to do: However, there are some caveats when implementing these methods naively. The plus button may stop working (no new tabs are added when you click it) and all default shortcuts are broken, their main menu items greyed out.
Last year, I had a full-time job from May until November and haven’t had much time to prepare for Mojave. Then it hit hard, and I am still tweaking my apps to look properly in Mojave’s Dark Mode. I welcome that macOS offers two modes now, .aqua and .darkAqua in programmer parlance. Because then I don’t have to implement a homebrew solution in all my writing applications.