Business

icon still not final

Core Data is like conversation: Take things out of context, and eventually, it will all come crashing down on you.

Me, in an attempt to begin this entry with something witty

ScreenFloat lets you keep visual references to anything you see on your screen floating above other windows using screenshots. It’s also a screenshot organizer.

Disclaimer: Estimated Time of Arrival, Pricing

I don’t do ETAs for my own products.
I’m a solo developer, I have multiple apps that need maintenance and updates, there are just too many moving parts for me to be able to estimate basically anything. And while that may be a serious lack of managerial skill: I accept that flaw and ignore it πŸ€·β€β™‚οΈ.

Regarding pricing, I don’t know what ScreenFloat 2 will cost yet. But I am resolved on its upgrade path: existing customers of ScreenFloat 1 will receive ScreenFloat 2 for free.

About this Journal

I thought it would be fun to chronicle my progress, struggles, successes, failures, struggles, failures, break-throughs, failures, and random stuff while developing ScreenFloat 2. That’s all.

Entry 2 – Core Data

This week, I’ve been busy with getting ScreenFloat 2’s migration to Core Data going and working, the first task being to decide on how I want to handle Core Data in the first place.

No multiple contexts, no problems. Right?

It’s been more or less established that, at the very least, you should have two managed object contexts when working with Core Data: One on the main queue for UI work, and another one on a background queue, for fetching and other “work”, so it doesn’t block the UI of the app.
This can make things tricky, because an object obtained on a background context should not and can not be used on the main queue to update the UI (and vice-versa). It has to be – for the lack of a better word – “converted” to a main queue object so that it can be used there.

So when I began working on migrating to Core Data, I thought, what if I could have the best of both worlds, with only one main queue context? Wouldn’t that solve all my potential problems?

John Hammond: “I’m not making the same mistakes again!”
Ian Malcolm: “No, you’re… making all new ones.”

Jurassic Park 2: The Lost World

What if the ScreenFloat app wasn’t aware about its Core Data nature at all? I could do all the Core Data stuff in a separate XPC service, and ScreenFloat would communicate with it to retrieve and update objects. The XPC service is its own process, so doing things there on the main queue context wouldn’t block the UI of ScreenFloat at all.

Sounds too good to be true? That’s because it is.

Issue #1 – Abstraction and Maintenance

To communicate with the XPC service, I’d have to create what I call “translator” classes that I send back and forth from and to the XPC service – classes that ScreenFloat understands (because it wouldn’t know about Core Data entities/objects), and the XPC service understands (so it can “translate” changes back to the Core Data store).
That would result in more work and maintenance. Anytime I wish to update a property, I would not only have to update the Core Data model and its entities, but also these custom “translator” classes.
And what about relationships in the Core Data model? Those would be a pain to handle this way.

Issue #2 – Bloating

ScreenFloat 2 will not only consist of the main app, but also a Share extension, at least.
That would mean to have to have this XPC service available to it as well, which in turn would mean having the XPC service inside the app twice – unnecessary bloat.

Issue #3 – iOS

iOS does not offer XPC services to 3rd party developers. But I want to have the same way of handling Core Data on all platforms ScreenFloat will support (I don’t want to have to do basically the same work twice), so it’s another no-go.

It was nice dreaming and wondering about this, but in the end, the more traditional approach to Core Data is still the best in my case.
Now I have a background queue context – used only for saving to disk -, on top of that the main queue context – used for updating the UI -, on top of that another background queue context – used for actually retrieving and editing stuff -, and on top of that an optional background queue context for work I might want not to persist/save, so it’s easy to discard. It works well so far.

Migrating ScreenFloat v1’s database to v2

I figured, the best way to get Core Data set up, working, and to see if my implementation works correctly, is to code it on-the-fly, adapting and changing it as needed. The best opportunity for this was to work on the migration of ScreenFloat 1’s dual-plist-file-based library. It’s the perfect case to see if my contexts are set up correctly, if conversion from one context to another works as expected, if all data and relationships are populated correctly, if it performs well, and if it saves to disk correctly.

On my MacBook Pro M1 Max, it imports the 699 Shots that currently reside in my ScreenFloat 1 library in less than 0.5 seconds (copying the files to their new destination, reading the plist files, creating the Core Data objects, and saving to disk).

It’s so fast that I had to slow it down artificially, so that the user can at least read that it’s upgrading the Shots library. If it weren’t for that, the progress bar would just be a weird, flashing artefact in the UI, leaving the user clueless as to what just happened. So instead of starting the migration process right after the Splash Screen appears, there’s a little delay, and then the process starts. When it finishes, there’s another short delay, and the Start using ScreenFloat button appears.

Migrating the library also got me thinking about what additional (meta)data I might need further down the road. For instance, ScreenFloat 1 doesn’t do “favorites” for Shots. So an “isFavorite” property would be a good idea.

Another one’s a bit more complex:
Users can put Shots into Categories to organize them. I’d like to store a bit of contextual information for that. For instance: when was this shot added to this category?
If a Shot could only be added to one category, that would be easy – just have an optional “dateAddedToCategory” property. But categories have a multiple-to-multiple relationship with Shots: a category can contain multiple Shots, and Shots can be added to multiple categories.
To my knowledge, the only way to do that is with another Core Data entity (let’s call it “CategoryShotMetadata“) and a many-to-one relationship to both the category and the Shot. When a Shot is added to a category, it automatically creates an object of this metadata entity, populates its “dateAdded” field, and sets up the relationships to the category and the shot. This makes it easy to fetch later: the Shot-to-metadata and Category-to-metadata is a one-to-many relationship (a Metadata object has one Shot and one Category, but a Shot/Category can have multiple Metadata objects). Now, the metadata object can be identified by the combination of its single category and single shot relationships.


I’ve been enjoying my time with Core Data so far (and I’m fully aware that this might change at any given moment πŸ˜‰ ) . It’s definitely more complex than my previous two-plist-file-approach, but – let’s be frank – Core Data is just better.

That’s it for this time.
Thank you for joining me. Feedback, input and questions are welcome: mail me, tweet me.
Take care! πŸ€—

Read more

Transloader – an app that lets you start downloads on your Macs, remotely from your iPhones, iPads, and other Macs – is now available in version 3.1.1 for both macOS and iOS.

v3.1.1 is a maintenance update which includes minor improvements and fixes.
– Now remembers previously selected Macs in Transloader and its Share extension
– The “local” Mac is now included in the Add Download dialogs
– Improved imagery for Macs and iOS devices
– Improved behavior of Transloader’s popover (when used as a menu bar app)
– Improved positioning of Transloader’s popover if the menu bar item is currently being truncated by macOS

– Fixes a bug where sometimes clearing all data from Transloader’s iCloud would fail
– Fixes a bug where copying preferences over from another Mac would confuse Transloader into thinking it is that other Mac
– Reduces the frequency of the appearance of rating requests from 6 to 9 months (if there’s been an update in between)

Links

Transloader Website
Transloader on the Mac App Store ($9.99 / € 9.99)
Transloader for Mac on Setapp
Transloader on the iOS App Store (free)
Transloader Usage Tips
Eternal Storms Software Productivity Bundle (includes Transloader, Yoink and ScreenFloat at ~25% off)

Enjoy πŸ€—

Read more

icon most likely not final

ScreenFloat 2 has officially entered “production”.
Apart from a bit of prototyping of various new features over the last couple of months and years, not a lot has happened in regards to ScreenFloat. But I feel now is the time to finally get it done.

ScreenFloat lets you keep visual references to anything you see on your screen floating above other windows using screenshots. It’s also a screenshot organizer.

Disclaimer: Estimated Time of Arrival, Pricing

I don’t do ETAs for my own products.
I’m a solo developer, I have multiple apps that need maintenance and updates, there are just too many moving parts for me to be able to estimate basically anything. And while that may be a serious lack of managerial skill: I accept that flaw and ignore it πŸ€·β€β™‚οΈ.

Regarding pricing, I don’t know what ScreenFloat 2 will cost yet. But I am resolved on its upgrade path: existing customers of ScreenFloat 1 will receive ScreenFloat 2 for free.

About this Journal

I thought it would be fun to chronicle my progress, struggles, successes, failures, struggles, failures, break-throughs, failures, and random stuff while developing ScreenFloat 2. That’s all.

Fundamental Decisions

Before I can start coding, there are a few decisions I have to make in order to be clear on where I want to go and what I want to achieve.

Decision 1 – Build on ScreenFloat 1’s code base, or start from scratch?

I began work on ScreenFloat 1 on March 11th, 2010.
Memory is still managed manually (for you youngster coders out there: google retain / release to know what I’m talking about).
Objective-C’s @property wasn’t even available yet back then.
It’s ancient!
In addition, it was one of my first apps, so ScreenFloat 1’s code is all over the place. And while I don’t think code has to be “pretty”, I do think it has to be readable and understandable; ScreenFloat 1 is neither.
So yes, I’ll definitely be starting ScreenFloat 2 from scratch.
Which my next decision factored into…

Decision 2 – Objective-C, or Swift?

Swift, of course. I love Objective-C (it’s got me this far), but I think by now it’s clear that the future is written in Swift. That’s not to say that if there wasn’t Swift, I wouldn’t love to continue working in Objective-C. However, with more and more frameworks being Swift only (for example, Widgets), I need to move on as well.
While this decision is of no consequence to users of the final product – a feature in an app should work no matter what language was used to program it -, it is quite consequential to me.
I began learning Swift earlier this year – my freeware developer tool BackLog is a first result of that – and I’ll continue to learn. For me, the easiest way to do that is “on the job”: to actually work on something I’m going to ship. Two birds with one stone.
Will that increase development time? Possibly.
Is it worth it? I believe so.

Decision 3 – Keep old storage model, or migrate to Core Data?

ScreenFloat 1’s “storage model” was two plist files (one for the shots library and associated metadata, and one for categories the user created in the Shots Browser) and a folder full of image files.
It worked ok, but I’d like something more sophisticated, robust and scalable.
That sounds like Core Data to me.
It’s not a new framework to me (thankfully – it is a lot to learn). I’ve been using it for a couple of internal tools, and for apps I’m maintaining for third parties.

As a side note, I do want to keep the “folder full of image files”. It makes them accessible in Finder, instead of being stored somewhere on disk in an opaque Core Data storage file.

Decision 4 – Core Data with CloudKit, or Core Data with custom iCloud/CloudKit sync?

I recently took to twitter to see what other developers thought about Core Data with built-in iCloud sync. The consensus was pretty much to stay away: it can be slow, very opaque as to what it’s doing, and thus difficult to debug.

Synchronisation is difficult to debug as it is, so I don’t want to make it any harder than it has to be.
Over the years, I’ve gained quite a bit of experience when it comes to syncing with iCloud / CloudKit (I manually sync with iCloud using CloudKit in Yoink for iPad and iPhone and Transloader), so I’m confident I’ll be able to write my own custom CloudKit sync solution for ScreenFloat 2.

Decision 5 – macOS, sure, but what about iOS/iPadOS?

ScreenFloat 2 will be available for Mac, as well as iOS/iPadOS.
So some code (most notably storage and sync) has to be able to run on all those platforms – something to consider going forward.

As with all my other apps, ScreenFloat 2 for Mac and ScreenFloat 2 for iOS will be developed for and tailored to each respective platform mostly separately, and so they will also be sold separately.

That’s it for this time.
Thank you for joining me. Feedback, input and questions are welcome: mail me, tweet me.
Take care! πŸ€—

Read more

Yoink for Mac, the drag-and-drop improving utility, is now available in version 3.6.8.

What’s New?

There’s now a preference for having Yoink dynamically provide JPEG and/or PNG data for TIFF, HEIF and/or WebP image files you drag out of it.

I’ve also fixed a couple of bug fixes and made some quality-of-life improvements, like having a dedicated “Pinned Copies” sub-menu in Yoink’s contextual menu’s Clipboard History.

Where to get Yoink

Website (+ free, 30-day demo)
Mac App Store
Setapp

As always, it’s a free update for existing customers of the app.

It requires macOS Sierra 10.12 or newer and runs natively on Apple Silicon and Intel Macs.
Yoink is available in English, German, French, Italian, Simplified Chinese, Japanese, Korean and Portuguese.

Enjoy πŸ€—

Read more