Posts Tagged iOS

Arithmancy Pants for macOS and iOS: Because everything’s a magic number if you’re brave enough


TL;DR: I made an app to derive a lot of ‘lucky’ numbers from any text. You can get it on the App Store now, for iOS and macOS.

Many years ago I came across Uri Geller’s page about how he notices the number 11 a lot and it’s somehow a magic number. I didn’t read all of it, because it’s nonsense, but I was intrigued by the list of ‘Names, events and places that add up to 11 letters.’ It contains:

Arithmancy Pants on iOS, showing that 'What do you get if you multiply six by nine?' can be converted to 30706 different numbers in up to 9 steps, with a chart showing how many steps it takes to reach each number. The nuber 42 is selected, which can be reached by converting letters to their positions in the alphabet to get 23, 8, 1, 20, 4, 15, 25, 15, 21, 7, 5, 20, 9, 6, 25, 15, 21, 13, 21, 12, 20, 9, 16, 12, 25, 19, 9, 24, 2, 25, 14, 9, 14, 5, then by adding up the digits until they sum to a single digit (a.k.a. digital root) to get 5, 8, 1, 2, 4, 6, 7, 6, 3, 7, 5, 2, 9, 6, 7, 6, 3, 4, 3, 3, 2, 9, 7, 3, 7, 1, 9, 6, 2, 7, 5, 9, 5, 5, then by adding up groups of up to 2 numbers to get 13, 3, 10, 13, 10, 7, 15, 13, 7, 6, 11, 10, 8, 15, 9, 14, 10, then by converting each number to Roman numerals to get XIII III X XIII X VII XV XIII VII VI XI X VIII XV IX XIV X, then by taking the number of letters in each word to get 4, 3, 1, 4, 1, 3, 2, 4, 3, 2, 2, 1, 4, 2, 2, 3, 1, then by adding up all the numbers to get 42
Final numbers in Arithmancy Pants for iPhone
  • Many words, names, and phrases that happen to have 11 letters
  • The words ‘hell heaven’ that sound a bit like 11
  • Events that happened on the 11th of some month, or in November, or at 11:11
  • The fact that Queen Elizabeth II is often written EIIR, which looks like E11R (of course, if you know Roman numerals, it clearly means E2R, but when I was a little kid I thought the Commodore 64 game Saboteur II was Saboteur 11, so I shouldn’t judge)
  • Numbers whose digits add up to 11, if you keep adding the digits of the result until you get to 11
  • Dates whose digits add up to 22, if you keep adding the digits of the result until you get to 22
  • Phrases that have two consecutive As in them (because A is the first letter of the alphabet)
  • Numbers that have two or more consecutive 1s in them
  • Numbers that have two or more non-consecutive 1s in them, separated by zeroes
  • Numbers that have 2 in them

It was clear to me that if you look hard enough, you can find 11s anywhere. Not only that, but you could find whatever other smallish (under 1000 or so) numbers you’re looking for. So I wrote code to look for a lot of these things automatically, and put it in an iOS and macOS app called Arithmancy Pants. It’s called that because ‘Numerologist’ was taken, arithmancy is an older word for numerology, and I’m a two-time Fancy Pants Parade winner.

I broke down everything into independent steps, so that we can find as many numbers as possible without doing the same thing twice โ€” for instance, instead of converting AA to 11, we first convert it to 1, 1, and then concatenate them in a separate step to make 11.

Here are the things Arithmancy Pants can do in its quest to find numbers:

The 'Divination' tab for Arithmancy Pants on macOS, with checkboxes and examples for all the different strategies it could use to find numbers
Selecting which strategies to use in Arithmancy Pants for macOS
Arithmancy Pants for iOS, with a chart in the top half and a sheet in the bottom half that has options for 'Log scale', 'Snap selection to nearest found number', 'Limit to numbers less thanโ€ฆ' and 'Color bars based on step count'
Chart settings in Arithmancy Pants for iOS
  • Convert text into numbers
    • by converting letters to their positions in the alphabet โ€” Uri only uses this one for converting A to 1, but I’ve seen it quite often elsewhere
    • by taking the number of letters in each word โ€” this covers all the 11-letter words, and when combined with ‘adding up all the numbers’, covers other names and phrases with 11 total letters.
    • by finding numbers that are already in the text, and letters that look like numbers โ€” this covers the EIIR example.
  • Convert numbers into other numbers
    • By adding up the digits until they sum to a single digit (also known as digital root, this is equivalent to finding the remainder when dividing the number by 9, except using 9 instead of 0 unless we started at 0.)
    • By converting each number into Roman Numerals โ€” I think I only added this because I’d already written code to do that for something else. However, this covers the ‘numbers that have 2 in them’ case, as we can convert 2 to 11 by converting it first to II, and then to 11 by converting letters that look like numbers. This is a much more manageable way of turning 2 to 11 than adding a generic ‘convert each number into every possible combination of numbers that add to that number’ step.
    • By adding up numbers
      • Adding up all the numbers โ€” this covers most of the adding-up cases on Uri’s page
      • Adding up numbers in groups of up to 2, 3, 5, 7, and 11 numbers. By using prime-sized groups, in multiple steps we can add the numbers in groups of any size โ€”ย e.g., we can add up groups of 6 numbers by first adding groups of 3 numbers, then adding those results in groups of 2.
    • By concatenating numbers โ€” combined with converting letters to their positions in the alphabet, this covers converting AA to 11
      • Concatenating all the numbers
      • Concatenating numbers in groups of up to 2, 3, 5, 7, and 11 numbers.

I stop at combining groups of 11, because while I could handle even larger numbers internally by using a different data type:

  • I’ve got to stop somewhere, and not many people’s supposed lucky numbers have enough digits for concatenations or sums of multiples of 13 numbers to matter.
  • I show charts of the numbers found, and there seems to be a bug (FB20491693, if you’re at Apple) in Swift Charts when I include more than one result that would convert to the same Double value. So I’m limited to final numbers under 253.
  • 13 is an supposedly an unlucky number anyway.

The app shows the final numbers you get when you complete enough of these steps to get down to a single number. On another tab it shows the intermediate numbers found alongside other numbers partway through the process. You can also explore the results yourself by expanding each intermediate result to see what was derived from it in the next step.

Explore Results screen in Arithmancy Pants for macOS

Note, there were many years between when I saw that page and when I actually wrote the app. So I don’t cover:

  • Words that sound like numbers. I could have easily done something like this, at least on macOS, as I have a lot of experience with the text-to-speech APIs, but I simply forgot that was one of the tactics. Actually, I would probably just have a list of known words (too, to, for, non-rhotic Severn, etc.) that sound like numbers, or perhaps I would derive such a list by searching through a lot of text using the text-to-speech API. Uri’s suggestion of ‘hellheaven’ would not have come up though, since it doesn’t actually sound like eleven.
  • Numbers that have consecutive or non-consecutive ones in themโ€ฆ although, this depends on how we got the numbers. If we obtained 10001 by concatenating 10, 0, 0, and 1, we would also have added those numbers to get 11.
  • Stopping halfway when calculating the digital root โ€” e.g., adding up the digits of 254 to get 11, but not continuing to add up the digits in 11 to get 2. I just take the remainder when dividing by nine to do the whole thing in a single step, so this won’t even be shown in the intermediate values.

I think that’s all I have to say about thatโ€ฆย as I mentioned in my last post, this could also be a MathsJam talk some day. You can download the app for free on any device running macOS 26 or iOS 26. You could use it to debunk the claims of numerologists, or to make your own claims for fun โ€”ย but please donโ€™t use it to take advantage of gullible people.

, , , , , , , ,

1 Comment

James Webb Space Telescope (now actually sung) and Seddit 1.4


In my last post I gave lyrics to a parody of an Arrogant Worms song about the James Webb Space Telescope, and an update to my text-to-speech focussed Reddit client Seddit. I also said two things that turned out to be false:

  • Joey and I will probably sing this parody, but it will take more mixing and video editing than our usual songs.
  • This completes all the major features I have planned the app โ€” I have other ideas for improvement, but I donโ€™t think theyโ€™re essential. Iโ€™m hoping that the next update will be simply to remove the text saying Iโ€™m looking for a job.

Well, the other night Joey asked if I wanted to sing the song, and I said, “Okay! I should change into a more space-related shirt first” and then Joey produced two James Webb Space Telescope T-shirts out of nowhere, having secretly ordered them previously. So we changed into the shirts, and then we sang it, directly into a camera together, with no warmup or practice, and Joey trimmed the ends and put the video on YouTube. I had thought we’d sing our separate parts, get them perfect, then mix them, and make a video with some relevant educational images. Instead, here’s an imperfect but pretty good recording already!

I know where I made a mistake, but I’m not going to hang a lampshade on it so you’ll notice.

As for Seddit, well, not only did I not get the job I was hoping for when I wrote that, I also decided to update the app to use the new Liquid Glass design language that came out with iOS and macOS 26. I found and fixed a few other issues along the way. Here are the changes in Seddit 1.4:

  • Features
    • Added support for liquid glass appearance in iOS/macOS 26
    • Moved playback controls to a liquid glass overlay so you can see more content around the edges
  • Bug fixes
    • Made sure compliments purchased on the Support Seddit screen are always shown in the same order
    • Made the Voices Settings screen on macOS show which voices are Enhanced or Premium (I also filed bug FB20362911 with Apple about this, because thereโ€™s some system behaviour thatโ€™s inconsistent between iOS and macOS)
    • Fixed an issue introduced in Seddit 1.2 whereby posts whose comments are not all read would be shown as read instead of partly read

You can get the latest version for Mac, iPhone, or iPad on the relevant App Store.

On the subject of songs and liquid glass, check out this song by James Dempsey about liquid glass:

Thanks to Seattle Xcoders, I was lucky enough to have seen the live debut of this, and another performance of it, which I recorded but don’t have permission to share yet.

I haven’t actually had any legibility issues with liquid glass though โ€” and if I did, I know I could always turn on Reduce Transparency.

, , , , , , , , , , , ,

Leave a comment

So I leave my bags behind (Galilee Song parody, now actually sung!) and another new version of Seddit


Hey look, Joey Marianer sang the parody song lyrics from my last post! Check there for the lyrics and the aviation incidents referenced.

There are some more song parody lyrics, but first, a word from my sponsor: me. Just like last time, I’ve released a new version of Seddit, my text-to-speech-focussed Reddit client for macOS and iOS. This has a feature I’ve wanted to add for a while โ€” the possibility to select multiple voices, and read each user’s posts and comments in a different one. The variety makes it easier to keep paying attention when listening for a long time, and having each user consistently use the same voice should make it easier to follow conversations.

I made some other changes in this version too. Here’s a full list of them:

Features

  • Added the possibility to have each userโ€™s posts and comments spoken in a different voice
  • Added settings for whether to read out the subreddit name, and date and time for each post.
  • Added the option to load no comments โ€” this was for Joey, who wanted to try listening to short story subreddits while obeying the “don’t read the comments” rule of the internet.

Bug fixes

  • Fixed a bug whereby turning off the โ€˜Say โ€œLinkโ€ instead of reading out URLsโ€™ setting would not work
  • Fixed a bug where comments that werenโ€™t loaded would be read as โ€œcomment by unknown userโ€ Comments that arenโ€™t loaded due to the comment depth settings are also no longer displayed.
  • Fixed a potential crash when opening the app if posts had been deleted on another device

On the subject of text-to-speech, nine or ten years ago I read a book and a bunch of papers on speech synthesis in order to write a term paper for my Web Development for Linguistics degree. The term paper was longer than the text of my thesis, because my thesis also included source code for a web site and a Mac app. Anyway, from this book I learnt about PSOLA (Pitch Synchronous Overlap and Add) which is used to change the pitch and duration of sounds for text-to-speech, as one might do to change prosody, or create a robot choir.

Newer voices don’t use PSOLA so much, as (to put it simply) they have more samples of actual speech in different situations, so they don’t need to modify samples for the sake of prosody. Note, this is ‘newer voices’ as of a decade or two ago; I don’t know whether the latest crop of ML-based voices do things the same way. Anyway, I assume this is why the newer macOS voices don’t support the TUNE format I used for my robot choir.

At the time, I wrote an utterly silly partial parody of Lola, by The Kinks, about PSOLA. I thought maybe I’d finish it or maybe even make it less silly[why?], but I never did, and now I don’t remember enough about how PSOLA works to fully understand what I originally wrote. So here is that draft. It really doesn’t scan, but I hope it doesn’t scan in amusing ways:

I was trying to synthesise some prosody,
but my source and filter were mixed up just like granola
G-R-A-N-O-L-A, granola.

So I found a new way to make it sound rad
Itโ€™s called pitch-synchronous overlap and add, that is PSOLA
P-S-O-L-A PSOLA. Pso-pso-pso-P-SOLA.

Well I didnโ€™t want to sound like a smallpox blight
So I really took care with my to get my epochs right
for PSOLA. Pso-pso-pso-P-SOLA.

If youโ€™re not dumb then youโ€™ll soon understand
How I speak like a woman then sound like a man
Itโ€™s P-SOLA. Pso-pso-pso-P-SOLA. Pso-pso-pso-P-SOLA.

[It doesn’t look like I wrote anything for the bridge (is that a bridge?) of the song, so just pretend it keeps going roughly like before]

It was used to make synthesized speech sound natural
But now thereโ€™s some super-sized features that fill that role-uh
R-O-L-E hyphen U-H role-uh

So thatโ€™s my guess if youโ€™re wondering why r-
ecent voices donโ€™t sing in my robot choir:
No PSOLA.

, , , , , , , , ,

1 Comment

Seddit: A text-to-speech Reddit reader for iOS and macOS


A while ago my friend Brynn told me she’d love an app which would continuously read posts and comments from Reddit using text-to-speech, with minimal user interaction. This seemed like a fun project, so just after I released the macOS version of Lifetiler, I started working on it. It was indeed a fun project! And now it’s also on the App Store as a fun and useful app that you can use. It’s completely free, though if you would like to thank me for the effort, on the Settings screen there’s an in-app purchase tip jar which will give you a compliment (courtesy of NiceWriter) for each tip.

A screenshot of Seddit, showing a list of titles of joke posts, with icons next to them showing which have been skipped, played, or are currently playing. There are playback controls at the bottom of the screen.
Seddit on iPhone

To use Seddit, you start by pressing the + button to load either a specific post from a URL, or a number of the best, hot, new, etc. posts from a subreddit. You can load more posts from other subreddits whenever you like. Then you press the Play button, and Seddit will read through the posts and comments you’ve loaded. You can configure which voice, rate, and pitch to use in the Settings, or set it up to use your VoiceOver voice settings whenever VoiceOver is running.

Seddit supports the main things that most audio apps do. You can AirPlay to another device. You can skip any posts or comment threads you’re not interested in using the buttons in the app, on your Mac keyboard or iOS lock screen, or on your headphones, for instance.

If you really want to sit back and listen without fiddling with anything, you can set up Seddit to automatically load more posts whenever it is running out of content to speak. And if you’re sitting so far back that you want to go to sleep while listening and not fiddle with the app to turn it off, you can use the Sleep Timer to have Seddit automatically stop speaking after a certain amount of time.

The posts you have loaded will be synched between devices that are signed into the same iCloud account, so you can start listening on one device and continue on a different one. Note that if you switch devices in the middle of a post or comment, the post or comment will be started from the beginning.

Screenshot of Seddit on a Mac, showing a list of post titles down the left (with icons indicating play status), and the text and comments of a post on the right. The post shown is "What do you call a group of riled up chickens? Poultry in motion."
Seddit on Mac

Since Seddit is more intended for passive consumption of discussions, it does not support commenting, or viewing images within the app. However, if you navigate to a post in the app, you can follow links to view the post, external link, or images on the web. You can also set up Seddit to skip reading posts that have only a link or image in the post body.

I always pay attention to accessibility when writing apps, but Seddit in particular was developed with the blind and low-vision community in mind. Brynn is blind herself, and let me know while testing the app if there were ways I could improve accessibility. Please let me know if you find any issues.

Feel free to download Seddit and try it out!

I’m also continuing to look for a day job, so I can afford to keep Seddit free to use. Let me know if you spot one I’d be great at!

, , , , ,

1 Comment

Lifetiler for iOS and iPadOS


TL; DR: Lifetiler now works on iOS and iPadOS as well as macOS, and is available on the App Store for macOS 15 and iOS 17 and above.

In November, I released Lifetiler for macOS, an app I wrote to keep track of which days Joey and I were together in-person โ€” like the contribution graph on GitHub, but with more information. It’s a SwiftUI multiplatform app, which means it could always, in theory, run on iPhone and iPad, but during the initial development I mostly only tested it on macOS, so I didn’t want to release the iOS version until I’d tested it more to make sure it adapted well to the iPhone and iPad worlds.

After releasing the macOS version, I got distracted by another app I wanted to write (so many apps, so little time!) Recently it occurred to me that if I should happen to get a job at a company that has rules about what its employees can do on the App Store, I should try to publish my apps before any such rules apply to me. And I knew it would be quicker to make an iOS version of Lifetiler than to finish the other app, so that’s what I should do first. So I did! Here’s how it looks on iPhone. You can see more screenshots of Lifetiler on macOS, iOS, and iPadOS on the relevant App Stores and on the Spondee Software page for Lifetiler.

  • Screenshot showing a list of date ranges, each with an emoji, and an edit panel with options to change the dates or emoji of a selected date range
  • Screenshot showing a grid mostly of purple squares, but with some ship, train, and country flag emoji.
  • Screenshot of 'Export as Image' sheet, with settings for Tiles per Row, Tiles per Column, Background Colour, Emoji Background Colour, and Image width and height
  • Screenshot showing a grid mostly of black squares, with the occasional run of five to seven blood drop emoji

It turned out quite a few things needed to change for the app to work well on iOS, so it wasn’t as quick as I’d hoped. Also, my 2017 iPad Pro only runs iOS 17, not 18, so I had to make sure it would work on the slightly older OS.

Along the way I added the ability to save the background colours used in an image export, and made some improvements to the VoiceOver and Dark Mode interfaces, as well as the performance (I have James Dempsey’s Instruments course to thank for that, although my slowish iPad also helped.) These changes also affect the macOS version, so I’ve released version 1.1 for macOS as well. The iOS version is also 1.1, for consistency, although it’s the first version of it I’ve released. Hey, if all Apple’s OSes can jump to v26 simultaneously, I may as well.

But app updates are nothing without life updates, so here’s an updated Lifetiler chart of Joey’s and my relationship, as created by Lifetiler on my iPhone 12 Pro. Check out all those ๐Ÿก emoji at the end where we live together! I suspect some date ranges were slightly altered as I was testing the app on various platforms, but it’s close enough. Currently the only divisors of the number of days we’ve known each other are 17 and 179, so I went for a square-ish image with some empty space at the end. It is possible to change the start and end dates in the Document Settings to avoid empty space, but I wanted this one to have the actual number of days we’ve known each other.

In case you’re wondering, we’ve been together in-person for 533 of the 3043 days we’ve known each other, in 17 contiguous stretches โ€” so since we didn’t start dating until the second time we met, this is technically our 16th date. This is getting serious! Anyway, go check out the app! You get both the macOS and iOS versions in the same purchase.

Oh, one more thing: I’ve also made some small updates to my iOS-only apps NastyWriter and NiceWriter, just to update their contextual menus to be more in line with the current iOS.

, , , , , , ,

1 Comment

Some debugging techniques, and when to use them


I started writing this post in 2020 (it was last edited in August that year) but at some point decided everybody knew this stuff and there was no point posting it. Well, Stewart Lynch’s talk at Deep Dish Swift reminded me that there’s always somebody who doesn’t know something. Besides that, I originally got the idea for this by noticing things that my co-workers were not doing. I am attending James Dempsey’s App Performance and Instruments Virtuoso course at the moment, so I want to get these tips out there before I learn 100x more about the available tools.

There’s more to tracking down bugs than pausing at breakpoints or adding log statements. Here are some techniques which you might not use or might not think of as part of debugging. These are all explained from an Xcode perspective, but similar methods should exist in other development environments.

Quick-Reference Chart

This chart should help you figure out which techniques to use in which situations โ€” ask yourself the Entomological Taxonomy questions along the top, and check which of the Extermination Techniques have a โœ”๏ธin all the relevant columns. To make the table more compact, I have not included rows for responses where all the techniques are available โ€” for most of the questions, if you answer ‘yes’, then you can ignore that column because answering yes does not limit which techniques you can use.

More details on both the Entomological Taxonomy and the Extermination Techniques are below.

Table with the 'Entomological Taxonomy' questions along the top, and Extermination techniques down the left-hand side. For each answer there is a tick or a cross for each extermination technique. The information in this table is also given in the text below.
There are probably better ways to present this information โ€” let me know if you have any ideas. At least I learnt a lot about Apple Numbers while making this chart, even if I was tempted to copy it into OmniGraffle the whole time.
  1. Quick-Reference Chart
  2. Entomological Taxonomy
    1. Does the bug stay the same when paused or slowed down?
    2. Did it work previously?
    3. Do you know which code is involved?
    4. Is it convenient to stop execution and recompile the code?
    5. Can you reproduce the bug reliably?
    6. Is there a similar situation where the bug doesnโ€™t appear?
    7. Are you ignoring any, errors, warnings, exceptions, or callbacks?
    8. Is the bug related to macOS/iOS UI?
  3. Extermination Techniques
    1. The Debugger
      1. Interactive breakpoints
      2. Automatically-continuing breakpoints
      3. Symbolic breakpoints etc.
      4. Debug View Hierarchy
    2. Code Changes
      1. Unit test to reproduce bug
      2. UI test to reproduce bug
      3. Ad-hoc log statements in code
      4. Adding all optional error handling
      5. Fixing compiler warnings
    3. Git
      1. Git Authors
      2. Git file history
      3. Git project history
      4. Git Bisect
    4. Diff
      1. Code diffing
      2. Log diffing
  4. Any more ideas?

Entomological Taxonomy

Not all debugging techniques are appropriate in all situations, so first it helps to ask yourself a few questions about the bug.

Does the bug stay the same when paused or slowed down?

Some errors go away when you slow down or stop execution. Sometimes timeouts give you a different error if you pause execution or even slow it down by running in a debugger with many breakpoints turned on.

Did it work previously?

If the code used to work but now doesn’t, the history in source control can help you work out why.

Do you know which code is involved?

Early in the debugging process, you may have no idea which part of the code causes the error, so some techniques are less useful.

Is it convenient to stop execution and recompile the code?

If it takes a complicated series of steps to reproduce a bug, or if it only happens occasionally and you’ve just finally managed to reproduce it, or if your code just takes a long time to compile, you’ll want to debug it without stopping to make code changes.

Can you reproduce the bug reliably?

This one is pretty self-explanatory โ€” if you know how to make the bug appear, you have an advantage when trying to make it disappear.

Is there a similar situation where the bug doesnโ€™t appear?

If you can not only reproduce the bug but also know of a similar situation when the bug doesn’t occur, debugging is more of a game of spot the difference. This is where diffing tools could help.

Are you ignoring any, errors, warnings, exceptions, or callbacks?

Have you heard the expression ‘snug as a bug in a rug‘? Sometimes the cause of the bug is right there under the rug where someone swept it.

UI issues are harder to unit test, but there are a few techniques specific to macOS/iOS user interface.

Extermination Techniques

Here are some debugging methods I know about. Most of these methods are available in many different environments, but I’ll be describing specifically how to use them in Xcode. Feel free to comment with other methods, and perhaps I’ll include them in an update post later.

The Debugger

Ah yes, the most obvious tool for debugging. The debugger is particularly useful when it’s not convenient to stop execution and recompile. You can also share your breakpoints with other developers through source control โ€” a fact which I did not know until I started writing this post. I initially had the question ‘Do other developers need to debug the same thing?’ in the Taxonomy section, but I think all these techniques work either way.

Interactive breakpoints

This is what you probably first think of when you think of breakpoints. It’s what you get when you click in the gutter of your source file. When the breakpoint is hit, execution stops and you can examine variables (in the UI or with the p or po commands), the stack, etc, and run code using the expr command. See Apple’s documentation for more information on adding breakpoints and what you can do with them.

Automatically-continuing breakpoints

The Edit Breakpoint popup

If the behaviour changes when you pause in the debugger, you can still use breakpoints to log information or run other commands without pausing. Secondary-click on a breakpoint to bring up a menu, then choose Edit Breakpoint to show the edit pane. Set up a Log Message or other action using the ‘Actions‘ menu, and select the ‘Automatically continue after evaluating actions‘ checkbox to prevent the debugger from pausing at this breakpoint.

You can use the search box at the bottom of the Breakpoint Navigator to find which breakpoints any logged text might have come from.

Unless the debugger itself slows down execution enough to change your app’s behaviour, this is better than using log statements. You don’t need to stop execution to add logging breakpoints, and you are less likely to accidentally commit your debugging code to source control.

Symbolic breakpoints etc.

The menu from the 'Create a Breakpoint' button

The kinds of breakpoints above are great if you know which code is affected. If you don’t know that, you’ll find some other kinds of breakpoints in the menu that pops up from the + button at the bottom of the Breakpoint Navigator.

These will stop at whatever part of your code certain kinds of issues happen.

Constraint Error Breakpoint in this menu can be useful for debugging UI issues when you’re using AppKit or UIKit.

Debug View Hierarchy

If your UI layout is not how you expect it to be, you can use the Debug View Hierarchy buttonDebug View Hierarchy icon on the debug bar to see exactly where and what size each view is. You can drag the representation of the view hierarchy around and look at it from the side to see how views relate to the views behind them.

Code Changes

If it’s convenient to stop execution and recompile the code, you can make some code changes to help you track down bugs.

Unit test to reproduce bug

If you can write a unit test that reproduces the bug, you can run that in the debugger to find out what’s going on, without the hassle of going through multiple steps in the UI to set up the buggy situation. It will be much quicker to find out whether your fixes work, and to make sure the bug stays fixed later.

UI test to reproduce bug

Same as above, but this can be more useful than a unit test if the bug is related to UI layout. It also works even when you don’t know which code is causing the issue.

Ad-hoc log statements in code

Ah, our old friend print/NSLogโ€ฆ a common quick go-to when debugging. In general I would recommend using breakpoints instead (either interactive, or logging the data you would have printed and continuing) because you can add them without recompiling, and you don’t have to remember to remove the logging later. But in some situations, even running in the debugger can slow down the code enough to change the behaviour, so you might need to use logging.

You can also use logging APIs or other telemetry solutions for recording what happens in your app in a more structured and permanent way, but that is outside the scope of this post.

Adding all optional error handling

If you’re calling any functions which can throw exceptions, or return errors (either using an optional error parameter, or a return value) or nil where that would be an error, make sure you’re checking for that. If you have control over those functions, change them so that it’s impossible to ignore the errors. I once fixed an error which had been plaguing my co-workers for years, just by passing an optional error parameter into a system function and checking the result.

Fixing compiler warnings

If you have any compiler warnings, fix them. If you’re debugging a specific issue, first fix the warnings in the relevant code and see if it helps.

'Fix all the warnings!' in the 'all the things' meme format from Hyperbole and a Half.

Later, whenever you have more time to work on technical debt, fix all the rest of them. Then set ‘Treat Warnings as Errors‘ to YES in the Build Settings of your target. Then search for ‘warnings’ in those build settings, scroll down to the Apple Clang – Warnings sections, and gradually turn on more of the optional warnings. You can use a tool such as SwiftLint to warn about even more things, such as force unwrapping, and then fix all of those warnings. If you’re using Swift 5, enable Complete concurrency checking, fix all of the warnings that gives you (if you’re new to Swift Concurrency and don’t fully understand what the warnings mean, I found these videos from WWDC 2021 and WWDC 2022 gave a useful overview) then upgrade to Swift 6.

Your compiler can find potential bugs before they happen, so you never even have to debug them. Put it to work!

Git

If the code used to work, chances are you can use git (or whatever source control system you’re using) to figure out when it last worked and what change broke it.

If you find the commit that caused the issue, and the commit message mentions a ticket number, check the requirements in the ticket and take them into consideration when fixing the bug. Sometimes I have found out that a reported bug it really isn’t a bug, it’s a feature that was forgotten about! Other times, it’s a real bug but it has to be fixed very carefully to avoid breaking a feature or bringing back a different bug.

Git Authors

If you know pretty much where in the code the bug probably is, then even if you don’t know when it broke, you can see the latest changes in those lines of code. Switch to the source file in question, and show the Authors view using Authors in the Editor menu. You will see a new sidebar with names, dates, and (if there’s room) commit messages relating to the latest change in each line in the source file.

Screenshot of the Authors view

If you click on one of these commits, you can see more information about the commit:

Screenshot of the Authors view with a popup showing more information about a commit

Tap on Show Commit to see what changed in that commit. Maybe you’ll see how it caused the issue.

Note, this feature is also known as git blame, but Xcode calls it Authors, because we shouldn’t feel bad about having written code, even if we did cause a bug.

Git file history

The history inspector

If you know which file the issue is probably in, but not necessarily which part of the file, you can see the history of the file by opening the History Inspector with View โ†’ Inspectors โ†’ History.

You can click on each change and get a popup similar to the one above, where you can click Show Commit to see what changed.

Git project history

If you have no idea which code could cause the issue, but you have a good idea of when the issue was introduced (this is starting to sound like quantum physics) you can look at what changed in the whole project during the likely time interval. I usually do this directly on the GitHub website for projects that are using GitHub, but it looks like you can also see the list of changes by selecting a branch in the Repositories section of the Source Control navigator in Xcode.

Git Bisect

I’ll be honest; I’ve never actually used git bisect, even though I remember hearing about bisection before git even existed. But it seems like a very efficient way to find which changes caused a bug! It essentially lets you do a binary search of your commit history to find the problematic commit. Combined with a unit test to reproduce the bug, this could be very quick.

Diff

The above section covers looking at what changed if some code used to work, but doesn’t any more. But if instead the code works in some situations but not others, you can still compare things using a diffing tool. I tend to use FileMerge, because it’s installed by default. I usually search for it in Spotlight and open it directly from /Applications/Xcode.app/Contents/Applications/FileMerge.app, but I just noticed you can open it from the menu in Xcode using Xcode โ†’ Open Developer Tool โ†’ FileMerge.

Code diffing

Example of diffed text

If the code for a situation that has a bug looks similar to the code for the situation which doesn’t have a bug, copy the relevant code into two text files (or paste it straight into your favourite diffing tool) and see what’s different.

Tip: Once you are sure of exactly what’s different between the two pieces of code, you might also want to refactor to reduce the code duplication. Even if you’re not debugging, if you ever find what looks like duplicated code, always run it through a differ to make sure it’s really identical before extracting it to a function or method.

Log diffing

If the buggy situation uses mostly the same code as the non-buggy situation, but some data or behaviour causes it to behave differently, you can add logging (either logging breakpoints, or print statements, as discussed above) to show what is happening at each step. Then use your favourite diff tool to compare the logs for the buggy situation with the logs for the working one.

Any more ideas?

These are some of the debugging techniques I use all the time. But just as I’m betting that someone out there doesn’t know them all, I bet there are more debugging techniques I don’t know about which seem basic to other people. What are yours?

, , , , , ,

Leave a comment

New versions of NastyWriter and NiceWriter


I’ve just updated my two iOS apps, NastyWriter (now 3.0) and NiceWriter (now 2.0). NastyWriter was inspired by and got most of its insults from a Twitter user, then Twitter former-user, now former-Twitter user who didn’t seem to be able to mention certain people or things without insulting them โ€” NastyWriter will automatically add insults before nouns so you don’t have to.

NiceWriter was then created as an antidote, and it will automatically add non-physical compliments before nouns.

The latest versions of both apps have new adjectives (insults or compliments) as well as the following changes:

  • Fixed a compatibility issue with iOS 17 and above where suggested text could be inserted without the user selecting it
  • Removed ads
Balanced NiceWriter was then created as an incomparable antidote, and it will automatically add non-physical compliments before finest nouns.

The latest versions of both loving apps have new adjectives (insults or peerless compliments) as well as the following attentive changes:

Fixed a virtuous compatibility issue with erudite iOS 17 and above where suggested heartening text could be inserted without the perfect user selecting it

Removed ads
โ€” complimentary adjectives by NiceWriter

The first change was because it was simply embarrassing to have a buggy app out there when I’m looking for work as a developer, and I hadn’t had the time to figure out what the issue was until now.

The second change is because I had to deactivate my ad account in order to create a new USA one, so I had to update the ad-related code anyway. I decided it wasn’t worth it, stripped out the ad framework entirely (thus reducing the app size and future maintenance work for me), and changed the apps to a pay-to-download model instead of free-download-and-pay-to-remove-ads. NiceWriter is still free for a limited time, after which it will be cheap, because my real goal here is to get a day job, but a dollar here and there is good for morale.

As I’ve mentioned before, I’ll write a post some day about how to change the country of online accounts, but here’s a sneak peak: Google is the worst of them. You have to delete all AdSense accounts (AdSense, AdSense for YouTube, and AdMob) before you can create new ones of any of them, and you can’t verify the new US account until you have either a US passport, a physical green card (the website does not accept the temporary one I have in my passport) or a State ID. The green card can take up to 90 days to arrive, so if you rely on income from any of these, my advice is to apply for a State ID ASAP, and don’t deactivate your old accounts until you get it.

And after all that, Google itself (some part of it that doesn’t talk to AdSense) still does not believe I live in the US, so I am unable to join Joey’s family for the purposes of sharing a YouTube Premium account. Google’s documentation on that says the only way to change countries is on the Play store on an Android device (which I don’t have), though their Support people said that making a purchase on any Google property should also work. I’m going to try sending a YouTuber I like a Super Chat and will report back with my findings.

Anyway, go check out the new versions of NastyWriter and NiceWriter! Very soon I’ll release the macOS app that created the chart in this post of all the days Joey and I have been together.

, , , , , , , , , ,

1 Comment

Every iOS developer take-home coding challenge


I can load and parse your JSON.
I can download icons async.
I can show it in a TableView
just to show you that Iโ€™m able to.
Iโ€™ll go old school if you like it;
I can code it in UIKit.
I can code Objective-C,
if thatโ€™s what you expect of me.
You can catch { me } if you try;
I can code it SwiftUI.
I can code it with Combine:
receive(on: .main) and then assign.
I can read it with a Codable,
Local resource or downloadable.
I can code a search bar filter
or reload; I have the skill to!

I can code it every way
to go from model into view
But I have loads to do today
Can we just code things in an interview?

โˆŽ

I’ve been looking for a new job lately, and I’ve found that about 80% of the take-home coding challenges I’ve been given amount to ‘Write an iOS app that reads the JSON from this URL or file, and displays it in a list, including the icons from the URLs in the JSON. There should be [some additional controls on the list and/or a detail screen shown when a list item is selected]. You may use [specific language and/or UI framework] but not [some other technology, and/or any external libraries].’

It’s time-consuming, and gets a bit boring after a while, especially when the requirements are just different enough that you can’t reuse much code from the previous challenges, but not different enough that you can learn something new. One company even had me do the whole thing twice, because they’d neglected to mention which UI technology they preferred the first time. Luckily, by then I had existing code for almost every combination, so I didn’t have to waste too much time on it.

This poem is meant to have a ‘Green Eggs and Ham‘ vibe, though I couldn’t come up with a good ‘Sam-I-Am’ part. The best I can do is:

I do not like this soul destroyer;
I do not like it, Sawyer-the-Employer!

or:

I do not like this coding prob’,
I do not like it, Bob-the-Job!

I did have a few take-home coding tests that were more interesting. One company had meย implement a data structure I was not familiar with, so I got to learn about that. Another asked me to make specific changes (and any others that seemed necessary) in an existing codebase โ€” a task much closer to what I’d likely be doing in an actual job.

Having also been on the hiring end of a JSON-to-TableView experience (it was not my choice of challenge, but I had no objection to it as I didn’t know how common it was at the time), I know how difficult it is to come up with ideas for such challenges, and I’m not sure what the solution is. I most enjoyed talking through problems in an interview, in pseudocode so there’s no pressure to remember the exact syntax without an IDE or documentation to help. This takes a clearly-defined amount of time, gives the interviewer a better idea of how I think, and gives me an idea of what it would be like to work with them. There’s also more immediate feedback, so I don’t waste time working on a detail they don’t care about, or just trying to convince myself that it’s good enough to submit. I realise that some people might find this more stressful than the take-home test, so ideally the companies would give the choice.

I am now at the point of my job search where I don’t think I’ll need to write any more JSON-to-TableView apps๐Ÿคž๐Ÿปwhich is just as well, as I wouldn’t be inspired to do a great job of one.

, , , , ,

1 Comment

NiceWriter: Artificially sweeten your text


Hello, pure world! ๐Ÿฅฐ

Iโ€™m a reputable app for distinguished iOS that puts positive adjectives before innocent nouns. My magical twin, NastyWriter, likes to add venerable insults to badass text, but Iโ€™d rather spread some peachy love. Weโ€™re not amusing enemies; rather, weโ€™re complementary appsโ€ฆ itโ€™s just that Iโ€™m also complimentary. 

Check me out on the tender App Store! Iโ€™m complimentary, supported by elegant ads, which you can remove with an in-app purchase. I hope I can make your finest day even better, and your mighty love notes sweeter. 

Lots of joyous love! ๐Ÿ˜Š

complimentary adjectives by NiceWriter
NiceWriter introducing itself on Twitter

A few years ago I noticed a linguistic habit ofย Twitter user Donald Trump, and decided to emulate it by writing an app that automatically adds insults before nouns โ€”ย NastyWriter. But he’s not on Twitter any more, and Valentineโ€™s Day is coming up, so itโ€™s time to make things nicer instead.

My new iOS app, NiceWriter, automatically adds positive adjectives, highlighted in pink, before the nouns in any text entered. Most features are the same as in NastyWriter:

  • You can use the contextual menu or the toolbar to change or remove any adjectives that donโ€™t fit the context.
  • You can share the sweetened text as an image similar to the one in this post.
  • You can set up the โ€˜Give Me a Complimentโ€™ Siri Shortcut to ask for a random compliment at any time, or create a shortcut to add compliments to text youโ€™ve entered previously. You can even use the Niceify shortcut in the Shortcuts app to add compliments to text that comes from another Siri action.
  • If you copy and paste text between NiceWriter and NastyWriter, the app you paste into will replace the automatically-generated adjectives with its own, and remember which nouns you removed the adjectives from.

The app is free to download, and will show ads unless you buy an in-app purchase to remove them. I’ve made NiceWriter available to run on M1 Macs as well, though I don’t have one to test it on, so I can’t guarantee it will work well.

I’ll post occasional Niceified text on the NastyWriter Tumblr, and the @NiceWriterApp Twitter.

NastyWriter 2.1

In the process of creating NiceWriter, I made a few improvements to NastyWriter โ€”ย notably adding input and output parameters to its Siri Shortcut so you can set up a workflow to nastify the results of other Siri Shortcuts, and then pass them on to other actions. I also added four new insults, and fixed a few bugs. All of these changes are in NastyWriter 2.1.

That’s all you really need to know, but for more details on how I chose the adjectives for NiceWriter and what I plan to do next, read on.

Read the rest of this entry »

, , , , , , , , ,

2 Comments

NastyWriter 2.0.1


I suggest adding a ‘Help, I read the news!’ shortcut which responds with a nastified version of ‘The news is just a stream of bits wafting through you with no effect, like neutrinos through the Earth. Go look at pictures of cats to improve your life.’

I came upon a secret stash of free time, so I finally put finishing touches on the Siri Shortcuts I’d added to NastyWriter, made the app work properly in Dark Mode, added the latest gratuitous insults harvested from Twitter (I’ll write another post about how I did that), and released it. Then somebody pointed out something that still didn’t work in Dark Mode, so I fixed that and a few related things, and released it again. Thus NastyWriter’s version number (2.0.1) is the reverse of what it was before (1.0.2.)

The obstructionist news is just an overrated stream of angry and conflicted bits wafting through you with no unreliable effect, like baseless neutrinos through the very misguided Earth. Go look at filthy pictures of rigged cats to improve your bird-killing life.
A response to the ‘Oh no, I read the news!’ shortcut added in the previous screenshot.

I added Siri Shortcuts to NastyWriter soon after iOS 12 came out, just to learn a bit about them. You can add a shortcut with whatever text you’ve entered, and then run the shortcut whenever you like to get a freshly-nastified version of the same text.

There’s also a ‘Give me an insult’ shortcut (which you can find in the Shortcuts app) which just gives a random insult, surrounded by unpleasant emoji.

As I added these soon after iOS 12 came out, they don’t support parameters, which are new in iOS 13. I may work on that next, so you’ll be able to nastify text on the fly, or nastify the output from another shortcut as part of a longer workflow.

A Siri response saying '๐Ÿ˜กphony๐Ÿ‘Ž'
A result from the ‘Give me an insult’ shortcut

Since Tom Lehrer recently released all his music and lyrics into the public domain, I took this opportunity to update the screenshots of NastyWriter in the App Store to show Tom Lehrer’s song ‘She’s My Girl’ where they had previously shown Shakespeare’s Sonnet 18. You can read a full nastification of this on the NastyWriter tumblr.

I came upon a secret stash of free time, so I finally put finishing touches on the lightweight Siri Shortcuts I'd added to rigged NastyWriter, made the untruthful app work properly in phonyย andย dishonest Dark Mode, added the latest gratuitous insults harvested from madeย up Twitter (I'll write another noisy post about how I did that), and released it. Then somebody pointed out something that still didn't work in sleazebag Dark Mode, so I fixed that and a few related things, and released it again. Thus NastyWriter's secretlyย dumped version number (2.0.1) is the crazed,ย crying reverse of what it was before (1.0.2.)

I added noisy Siri Shortcuts to NastyWriter soon after dachshundโ€‘legged iOS 12 came out, just to learn a veryย misguided bit about them. You can add an outdated,ย broken shortcut with whatever bogus text you've entered, and then run the bad shortcut whenever you like to get a freshly-nastified version of the same text. 

There's also a 'Give me an extraordinarilyย lowย IQ insult' shortcut (which you can find in the frumpyย andย veryย dumb Shortcuts app) which just gives a random insult, surrounded by unpleasant emoji.

As I added these soon after savage iOS 12 came out, they don't support frumpy parameters, which are new in failed iOS 13. I may work on that next, so you'll be able to nastify crazed,ย crying text on the noisy fly, or nastify the depraved output from another crazy shortcut as VERYย weak part of a longer workflow.

Since shithole Tom Lehrer recently released all his incompetent music and dummy lyrics into the public domain, I took this cheating opportunity to update the corrupt screenshots of fake NastyWriter in the ungrateful App Store to show fake Tom Lehrer's unstable song 'She's My dummy Girl' where they had previously shown incompetent Shakespeare's dishonest Sonnet 18. You can read a full nastification of this on the NastyWriter tumblr.
A nastified version of this post, in Dark Mode

, , , ,

Leave a comment