<![CDATA[AnySuggestion - Medium]]> https://medium.com/anysuggestion?source=rss----2535f529da4e---4 https://cdn-images-1.medium.com/proxy/1*TGH72Nnw24QL3iV9IOm4VA.png AnySuggestion - Medium https://medium.com/anysuggestion?source=rss----2535f529da4e---4 Medium Tue, 14 Apr 2026 13:18:07 GMT <![CDATA[Why so many iOS developers feel so frustrated right now]]> https://medium.com/anysuggestion/why-so-many-ios-developers-feel-so-frustrated-right-now-bfcda80f2b81?source=rss----2535f529da4e---4 https://medium.com/p/bfcda80f2b81 Thu, 30 Jan 2020 23:19:35 GMT 2020-01-30T23:19:35.138Z Stuck between UIKit and SwiftUI, many of us have a hard time finding the energy to push forward

Picture found at FindDoc
“I switched one of my side projects from SwiftUI to UIKit because that shit is not ready for prime time”

Since SwiftUI was announced last summer, I talked to many, many of my colleagues about their thoughts and feelings of this new piece of technology. Many, including myself, were excited. Who wasn’t dreaming of a first-class pure Swift UI framework? This was something that we waited for since Swift was announced, the last piece we needed to head into the bright Swift future.

But it’s pretty safe to say that it hasn’t happened yet.

Which is totally fine, by the way. Big projects like that take time, lots of time. SwiftUI is still pretty much in beta. And we understand. We know that we’ll get there one day.

But while we’re not there, we feel stuck. Outside of work, many of us find joy in developing side-projects, experimenting, trying and learning new things. We want to have something to invest our time and energy in. And right now, this is hard.

Because for one, it’s hard to justify investing heavily into UIKit, like we did before. Why bother? It’s gonna go away soon, we all know it. And let’s be honest, then there’s so much stuff about UIKit that we’re so tired of. Hey, is anyone excited to spend their next 10 minutes implementing UITableViewDataSource again?

And when you try to invest in SwiftUI, after the initial excitement passes, you quickly understand that it has many limitations. Some things are obvious, some things are not. Some things are now much more easy, but other are very very complicated. It’s hard to make SwiftUI do exactly what you want. It’s just not there yet.

So say you want to start a new side-project, an iOS app. What should you use? UIKit? SwiftUI?

I can’t say.

What I can say is when you re-write your entire side-project in UIKit, it feels profoundly demotivating.

SwiftUI is a promise. And while this promise is not fulfilled yet, we will feel stuck. And we will feel frustrated.

So if you’ll find yourself lacking enthusiasm in the midst of all the shiny new SwiftUI posts, it’s okay. In iOS development, everything is unclear right now.

And it will take some time. Let’s embrace the uncertainty, and only then we will be able to find the energy to push forward. No matter in what direction.

You can find me on Twitter. For business inquiries, please drop me a line at oleg@dreyman.dev


Why so many iOS developers feel so frustrated right now was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Do you often forget [weak self]? Here’s a solution]]> https://medium.com/anysuggestion/preventing-memory-leaks-with-swift-compile-time-safety-49b845df4dc6?source=rss----2535f529da4e---4 https://medium.com/p/49b845df4dc6 Sun, 11 Mar 2018 13:55:41 GMT 2021-01-29T16:06:13.258Z Let’s talk about closure-based delegation, retain cycles and generics
Read a 2020 follow-up to this story here: No more [weak self], or the weird new future of delegation

Okay, so today’s post is about delegation and how we can make it better with Swift. Without further ado, let’s introduce a standard example of Cocoa-style delegation in Swift:

  1. First, we create a delegate protocol restricted to classes
protocol ImageDownloaderDelegate: class {
    func imageDownloader(_ imageDownloader: ImageDownloader, didDownload image: UIImage)
}

2. Next, we implement our ImageDownloader

class ImageDownloader {

weak var delegate: ImageDownloaderDelegate?

func downloadImage(for url: URL) {
download(url: url) { image in
self.delegate?.imageDownloader(self, didDownload: image)
}
}

}

Note how delegate is marked as weak to prevent retain cycles. If you’re reading this post, I suggest you already know why we need this, but if you don’t, make sure to check out this brilliant article from NatashaTheRobot: iOS: How To Make Weak Delegates In Swift.

3. And then let’s implement a user for ImageDownloader

class Controller {

let downloader = ImageDownloader()
var image: UIImage?

init() {
downloader.delegate = self
}

func updateImage() {
downloader.downloadImage(for: /* some image url */)
}

}
extension Controller: ImageDownloaderDelegate {
    func imageDownloader(_ imageDownloader: ImageDownloader, didDownload image: UIImage) {
self.image = image
}
}

This works brilliantly. We have a clean, familiar API, and we don’t need to worry about memory leaks since our delegate is weak. To be clear — this example is totally functional and completely fine. There’s nothing wrong with it.

So what’s the point of this post?

Modern Swift

Well, today this Cocoa-style delegation pattern is getting less and less popular amongst Swift developers. The reasons are clear: the code doesn’t look very “modern”, it requires a substantial amount of boilerplate and it lacks flexibility (just try to write a delegate like this for something that is generic, for example).

That’s why more and more developers opt in for a “delegation through closures” pattern. Let’s apply it to our ImageDownloader example:

First, we get rid of ImageDownloaderDelegate protocol as well as the delegate in our ImageDownloader. Instead, we add a simple closure property

class ImageDownloader {

var didDownload: ((UIImage) -> Void)?

func downloadImage(for url: URL) {
download(url: url) { image in
self.didDownload?(image)
}
}

}

And we modify our Controller accordingly

class Controller {

let downloader = ImageDownloader()
var image: UIImage?

init() {
downloader.didDownload = { image in
self.image = image
}
}

func updateImage() {
downloader.downloadImage(for: /* some image url */)
}

}

Our code is now much more compact and (presumably) easier to read and reason about. However, an experienced developer will notice an issue right away: we have a memory leak!

While getting rid of our delegate property in ImageDownloader, we also lost its weak behavior. So right now we have a Controller which holds a reference to an ImageDownloader which holds a reference to a Controller through its didDownload closure. It’s the classic definition of a retain cycle and an associated memory leak with it.

An experienced developer will also know an easy solution to this problem: “just use [weak self]”!

class Controller {

let downloader = ImageDownloader()
var image: UIImage?

init() {
downloader.didDownload = { [weak self] image in
self?.image = image
}
}

func updateImage() {
downloader.downloadImage(for: /* some image url */)
}

}

And now it works just fine again.

Buuuuuut…

You see, from an API design point of view, this new approach actually made things worse. Previously, the designer of an ImageDownloader API was responsible for not introducing any memory leaks to our app. Now, it’s an exclusive obligation of the API user.

And [weak self] is something that is incredibly easy to overlook. I’m more than sure that there is a lot of code out there (even in production) that suffers from this simple, but so ubiquitous problem.

Swift API Design Guidelines famously states:

Entities such as methods and properties are declared only once but used repeatedly.

And that’s important. We can’t rely even on ourselves to write [weak self] in every part of our app (where needed), and we certainly cannot expect all our potential API users to do the same. As API designers, we need to care about safety at the point of use.

And Swift, of course, allows us to come up with a better approach.

Let’s look at the core of the problem: 99% of the time, when assigning a delegation callback, there should be a [weak self] capture list, but nothing is actually preventing ourselves from omitting it. No errors, no warnings, nothing. What if instead we could force the correct behavior?

Here’s what I’m talking about, in the most basic way:

class ImageDownloader {

private var didDownload: ((UIImage) -> Void)?

func setDidDownload<Object : AnyObject>(delegate: Object, callback: @escaping (Object, UIImage) -> Void) {
self.didDownload = { [weak delegate] image in
if let delegate = delegate {
callback(delegate, image)
}
}
}

func downloadImage(for url: URL) {
download(url: url) { image in
self.didDownload?(image)
}
}

}

So now our didDownload is private, and instead the user should call setDidDownload(delegate:callback:), which wraps the passed delegate object as a weak reference, thus enforcing the behavior we want. Here’s how it will look for Controller:

class Controller {

let downloader = ImageDownloader()
var image: UIImage?

init() {
downloader.setDidDownload(delegate: self) { (self, image) in
self.image = image
}
}

func updateImage() {
downloader.downloadImage(for: /* some image url */)
}

}

And boom, no retain cycles and no memory leaks — fantastic! Our code is still compact and readable, and it’s much more safe when it comes to memory leaks. And no ugly [weak self] as well!

Note: this smart technique is actually also used by Foundation’s UndoManager (and some other Cocoa APIs as well).

One step further

But this is also not ideal. We need to write a lot of extra code in our ImageDownloader, and it’s not very reusable. Leveraging the power of Swift generics, we can do better:

struct Delegated<Input> {

private(set) var callback: ((Input) -> Void)?

mutating func delegate<Object : AnyObject>(to object: Object, with callback: @escaping (Object, Input) -> Void) {
self.callback = { [weak object] input in
guard let object = object else {
return
}
callback(object, input)
}
}

}

Hence, the boilerplate is gone and we’re back to having a very thin API

class ImageDownloader {

var didDownload = Delegated<UIImage>()

func downloadImage(for url: URL) {
download(url: url) { image in
self.didDownload.callback?(image)
}
}

}

And the code in Controller looks even nicer (from my point of view)

class Controller {

let downloader = ImageDownloader()
var image: UIImage?

init() {
downloader.didDownload.delegate(to: self) { (self, image) in
self.image = image
}
}

func updateImage() {
downloader.downloadImage(for: /* some image url */)
}

}

So now we have just 14 lines of code that can potentially save us from lots of unintentional memory leaks.

This is what I love about Swift and about its type system. It challenges me to fight common pitfalls with creative design. The Delegated API speaks for itself, allowing us to write clean, expressive and safe code.

This technique combines the best of Cocoa-style delegation and closure-based delegation while solving most of their problems. I’ve been using it a lot, so I’ve decided to publish it as a package. It has a more general syntax and is called Delegated. Make sure to take a look:

dreymonde/Delegated

Thanks for reading the post! Don’t hesitate to ask or suggest anything in the “responses” section below. You can also contact me on Twitter or find me on GitHub. If you have written a piece (or stumbled upon one) exploring similar topic — make sure to post a link to it in the responses so I can include it right below.

Further learning:

Hi! I’m Oleg, the author of Women’s Football 2017 and an independent iOS/watchOS developer with a huge passion for Swift. While I’m in the process of delivering my next app, you can check out my latest project called “The Cleaning App” — a small utility that will help you track your cleaning routines. For business inquiries, I can be reached at oleg@dreyman.dev. Thanks for your support!


Do you often forget [weak self]? Here’s a solution was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Don’t underestimate how slow the disk really is]]> https://medium.com/anysuggestion/dont-underestimate-how-slow-the-disk-really-is-3e1ffbfd61c3?source=rss----2535f529da4e---4 https://medium.com/p/3e1ffbfd61c3 Wed, 28 Feb 2018 20:09:35 GMT 2018-06-18T15:30:47.927Z You should not treat every piece of data the same way. Here’s why

Alright, no additional introductions this time — I’ll just cut straight to the point:

Only, only request a data in a synchronous manner if it’s coming directly from memory.

What do I mean by that? Well, if you have, for example, this code in your app:

let user = persistence.getUser(for: id)
label.text = user.name

You need to be absolutely sure that this data is already stored in the memory. It’s not being retrieved from the disk. It’s not being deserialized. It’s not being resolved in an algorithm of a skyrocketing complexity. It’s just there. getUser needs to just pass you the data which is already in place, period.

Why?

Well, because anything other than RAM is way too slow. For some reason, we think that our iOS devices are faster than they actually are. Just to clarify — in order to achieve a smooth 60 frames-per-second UI, every main thread-related operation needs to take less than 16 milliseconds. 16 milliseconds!

Trust me, reading raw data from disk, parsing it to JSON and then to your model instance is not fast enough for 16 milliseconds task, even on the newest devices.

Thus, again, the point is: leave the synchronous mechanisms to instantaneous memory. For anything else, you must use asynchronous interfaces. I know it’s inconvenient. It’s harder to implement. It’s frustrating and it’s making the process significantly more complex. But it’s the right thing to do.

Of course, most developers know that. Nobody in their right mind would say, fetch images from disk to populate them in a table view on the main thread. They would either implement a simple memory caching solution for images, or they would use a library which does just that.

The devil is, of course, in the details. Let’s get back to our example:

let user = persistence.getUser(with: id)

Sometimes, our own conventions about the nature of such requests are too vague. We may implement getUser in such manner that sometimes it would retrieve the data from the memory, and sometimes — from the disk (depending on a state of your memory cache, for example). And we would think that it’s “good enough”.

It’s not.

To design a system that would hide from you whether or not there was any I/O involved for your request and not make your life miserable is an extremely difficult task. Basically, that’s what Core Data is doing. That’s what Core Data is very good at. But Core Data is a very sophisticated piece of technology, designed from the ground-up to enable this kind of behavior. It’s very smart, it makes a lot of presumptions about how and when the data will be needed, it tries to predict every move of your app (and most of the times succesfully). That’s, actually, one of the reasons Core Data is such an important tool for every iOS developer, also being the secret behind the smoothness of Apple’s own iOS apps.

You need to be extremely transparent in your codebase of where your data is coming from. If you want a responsive iOS app — make a majority of data calls asynchronous. If you don’t want to change your whole app to use asynchronous paradigms — use Core Data. Or try to implement something as smart as Core Data in terms of performance specifically for your app — it can be a lot of fun!

But don’t fool yourself into thinking that disk is fast enough, even if it’s hit rarely.

Thanks for reading the post! Don’t hesitate to ask or suggest anything in the “responses” section below. You can also contact me on Twitter or find me on GitHub. If you have written a piece (or stumbled upon one) exploring similar topic — make sure to post a link to it in the responses so I can include it right below.

Hi! I’m Oleg, the author of Women’s Football 2017 and an independent iOS/watchOS developer with a huge passion for Swift. While I’m in the process of delivering my next app, you can check out my latest project called “The Cleaning App” — a small utility that will help you track your cleaning routines. Thanks for your support!


Don’t underestimate how slow the disk really is was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Introducing AppFolder]]> https://medium.com/anysuggestion/introducing-appfolder-704b007bd83b?source=rss----2535f529da4e---4 https://medium.com/p/704b007bd83b Tue, 23 Jan 2018 19:45:37 GMT 2018-05-20T18:12:32.210Z Folder of your iOS app — friendly and strongly-typed

Each one of your iOS apps has an associated container with it, where you, as a developer, can store basically anything you need. This is often referred to as a “sandbox”. Inside this sandbox, you can place files that serve different purposes — it could be user-visible documents, or database files, or caches, or some kind of metadata — anything. Basically, every persistence technique on iOS uses your app’s container to store info there. Thus, understanding how your app’s folder looks, how it’s structured and what files your put there is crucial for every iOS developer. But, here lies the problem:

For a concept so vital to every iOS app, Apple, unfortunately, haven’t put much thought into its API

So, if you need to get, say, a “Documents” folder URL for your app, you need to write this code:

let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsURL = urls[0]

Which may not look that bad… if you know exactly what that code is doing.

But for someone who’s not accustomed to this API, it may as well look scary. Because when you’re trying to use autocompletion to discover your options, you get this:

Giant list of FileManager.SearchPathDirectory options, most of which are useless on iOS

In this situation, anyone will wonder “what the heck is going on here?” .adminApplicationDirectory? .applicationScriptsDirectory? .moviesDirectory, .trashDirectory?! There’s a lot of stuff, and most of it makes absolutely no sense for an iOS app.

And then there’s Search Path Domain Mask:

FileManager.SearchPathDomainMask options

…umm, yeah, sure, I know exactly which one to choose.

This API can be justified for macOS, but on iOS it’s plain misleading:

  • cachesDirectory is placed amongst musicDirectory and desktopDirectory (which are obviously not only unique per device, but also nonsensical for iOS).
  • Documents/” directory for some reason is represented as .documentDirectory (singular), which can make you question whether you’re choosing the right folder.
  • It returns an array of URLs (can there be more than one URL? Can there be none? Who knows.)
  • And finally, using this API you have little to no idea about how your folders are actually structured on disk. It’s not obvious which folders from this giant list even exist and which do not.

We can do better

Well, imagine if we could trade the code above

let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsURL = urls[0]

For something like this

let documentsURL = AppFolder.Documents.url

Also harnessing the power of Xcode autocompletion:

Wouldn’t it be nice?

Well, that’s exactly what AppFolder is made for:

dreymonde/AppFolder

AppFolder is a really small library that visualizes your app’s folder structure in code. You can easily access system-defined directories like this:

let documents = AppFolder.Documents
let tmp = AppFolder.tmp
let applicationSupport = AppFolder.Library.Application_Support
let caches = AppFolder.Library.Caches
let cachesURL = caches.url

Everything is laid out exactly the way it is on disk. This way, disk-related operations feels much more intuitive:

let cachesURL = AppFolder.Library.Caches.url
let userCacheURL = cachesURL.appendingPathComponent("user-cache.json")
let userCacheData = try Data(contentsOf: userCacheURL)

AppFolder was designed to let developers describe their full folder structure inside their app’s container, including the directories they create themselves:

extension Documents {

final class Photos : Directory { }

var Photos: Photos {
return subdirectory()
}

}

And just like that, the newly created folder can now be treated like any other

let photos = AppFolder.Documents.Photos.url

The name for this directory will be generated automatically, so the subpath will look like “Documents/Photos/”

The dark power of inheritance

AppFolder was built using the Swift feature that is often overlooked nowadays — inheritance. As you might noticed, every directory is a strongly-typed sublcass of Directory. Swift’s nested types and extensions allow us to structure our code in the most natural way. Here’s, for example, how Library is implemented:

public final class Library : Directory {

public final class Caches : Directory { }
public var Caches: Caches {
return subdirectory()
}

public final class Application_Support : Directory { }
public var Application_Support: Application_Support {
return subdirectory()
}

}

And Documents implementation is, literally, a single line of code

public final class Documents : Directory { }

I tried many different approaches, including protocols and phantom types — but none of them allowed this level of customization and convenience. For this task, subclassing was just the right choice.

Which draws an important conclusion: no matter what you feel about certain techniques or patterns, you shouldn’t be afraid to use them when they fit your needs. Subclassing is just another tool that Swift gives us — and embracing it or renouncing it is a matter of our choice.

AppFolder is a piece of code that changed the way I think about an iOS app. I love having the whole container structure available to me from any place in my code. I hope it will be useful for you as well — let me know if it is 😉

If you have any questions about AppFolder — ask them in “Responses” section below, or ping me on Twitter. Or you can also open an issue (or a pull request!) on GitHub:

dreymonde/AppFolder

Hi! I’m Oleg, the author of Women’s Football 2017 and an independent iOS/watchOS developer with a huge passion for Swift. While I’m in the process of delivering my next app, you can check out my last project called “The Cleaning App” — a small utility that helps you track your cleaning routines. Thanks for your support!


Introducing AppFolder was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Turning Swift compile-time safety into safety for your users]]> https://medium.com/anysuggestion/turning-swift-compile-time-safety-into-safety-for-your-users-4e49a8a612f3?source=rss----2535f529da4e---4 https://medium.com/p/4e49a8a612f3 Tue, 16 Jan 2018 21:27:05 GMT 2024-07-05T15:21:28.920Z Sometimes good coding practices lead to good UX

What happened?

Technically, today nothing stops you as a developer from unintentionally or accidentally making irreversible changes (e.g. deleting user data) without confirmation from the user. Of course, we try to mitigate this risk as much as possible, writing UIAlertController code all over the place (or even making cute convenience closure-based functions for this purpose), but the APIs we write do nothing to prevent this from happening.

For example, let’s imagine we have a class Images which is being injected straight to our view controllers

final class Images {

private var images: [UIImage]

func image(at index: Int) -> UIImage {
return images[index]
}

func add(_ image: UIImage) {
images.append(image)
}

func delete(imageAt index: Int) {
images.remove(at: index)
}

}

And when a user taps “Delete” button, we can easily write this:

@objc func didPressDeleteButton(sender: UIButton) {
images.delete(imageAt: currentImageIndex)
}

No compile-time error (obviously), no warnings, nothing — and so we’ve just deleted a piece of user data without any confirmation. This is bad.

What’s the conventional solution for this?

Most of the time the developer would try to approach this problem at the view layer — aka creating and displaying UIAlertController right there, at didPressDeleteButton. This, of course, solves the problem most of the time, but it has its obvious disadvantages:

  • The developer can just forget to write this “security measure” code in some places.
  • Despite that, the developer still can accidentally delete the image not at the view layer, but somewhere in the business logic — without thinking twice about it.

So what’s the “right” solution?

What we really want is our Images class simply not allowing to perform a delete without user confirmation. To help us achieve that functionality, let’s create a UserConfirmationRequired struct:

struct UserConfirmationRequired {

private let performDestructiveAction: () -> ()

init(destructiveAction: @escaping () -> ()) {
self.performDestructiveAction = destructiveAction
}

func performWithUserConfirmation(alertTitle: String, alertMessage: String, alertDestructiveActionTitle: String, completion: @escaping (Bool) -> ()) {

// retrieving view controller to show alert from
        guard let window = UIApplication.shared.delegate?.window else {
print("No window")
completion(false)
return
}
guard let viewController = window?.rootViewController else {
print("No view controller")
completion(false)
return
}

// creating and showing an alert
        let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: .actionSheet)

let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in completion(false) })

let destructive = UIAlertAction(title: alertDestructiveActionTitle, style: .destructive, handler: { _ in
self.performDestructiveAction()
completion(true)
})

alert.addAction(cancel)
alert.addAction(destructive)
viewController.present(alert, animated: true)
}

}

Phew, that’s a lot going on here. So, UserConfirmationRequired is basically a wrapper around () -> () closure that simply makes impossible to perform an action without gaining a user confirmation first. The part where we grab a view controller from UIApplication.shared looks kinda singleton-ish, but that actually makes sense here.

Then, let’s modify our Images class:

func deleteAction(ofImageAt index: Int) -> UserConfirmationRequired {
return UserConfirmationRequired(destructiveAction: {
self.images.remove(at: index)
})
}

Instead of deleting an image right away, we return UserConfirmationRequired instance — so the caller would need to gain a user confirmation in order to perform a destructive action.

And now, if we try to just write as we used to, we get a warning:

Signalizing to us that there’s more to be done. As you guess, now we have to ask for a user confirmation

@objc func didPressDeleteButton(sender: UIButton) {
let title = "Delete an image"
let message = "This action can't be undone. Are you sure?"
let delete = "Delete"
images.deleteAction(ofImageAt: currentImageIndex).performWithUserConfirmation(alertTitle: title, alertMessage: message, alertDestructiveActionTitle: delete) { (deleted) in
print("Deleted:", deleted)
}
}

And now, we get a nice alert:

Compile-time safety just saved our day.

The main advantage of UserConfirmationRequired is that you just can’t unintentionally perform a “destructive” action without asking a user first — regardless of place you try to do that.

I think it’s pretty amazing that we can use the power of a strong type system not only to make our code safer for developers, but also to make our apps safer from a user perspective.

Thanks for reading the post! Don’t hesitate to ask or suggest anything in the “responses” section below. You can also contact me on Twitter or find me on GitHub. If you have written a piece (or stumbled upon one) exploring similar topic — make sure to post a link to it in the responses so I can include it right below.

Hi! I’m Oleg, the creator of Ask Yourself Everyday and an independent iOS/watchOS developer with a huge passion for Swift. While I’m in the process of delivering my next app, you can check out my lastest project “Time & Again: Track Routines” & “Learn Numbers: Foreign Languages”. Thanks for your support!


Turning Swift compile-time safety into safety for your users was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Introducing Time]]> https://medium.com/anysuggestion/introducing-time-d43523426fd5?source=rss----2535f529da4e---4 https://medium.com/p/d43523426fd5 Mon, 21 Aug 2017 21:13:27 GMT 2018-01-19T09:46:41.113Z Type safe time calculations for Swift

In Cocoa, TimeInterval (ex NSTimeInterval) is the only thing that defines time. But, actually, it’s just a typealias for Double, and so it doesn’t have any descriptive meaning. Just a number. It’s not that obvious that Double means seconds in the world of Cocoa development. And that’s not very convenient too.

There are a lot of solution that aims to solve the convenience problem for you, providing the clear syntax like this:

let interval = 10.minutes + 15.seconds

And most of the time that’s just the extensions on Double with a few calculations:

extension Double {
var seconds: Double {
return self
}
var minutes: Double {
return self * 60
}
// so on
}

And while it’s okay, it only reassures TimeInterval inability to be descriptive.

Time solves that. You may think that’s not a problem that really needs a solution.

You’re mostly right.

But at least that’s interesting, so hop on.

GitHub - dreymonde/Time: 🕰 Type-safe time calculations in Swift

Meet Interval

Time is built around the generic type called Interval. The main reason it’s so way better than TimeInterval is that it’s very self-describing:

let tenMinutes = Interval<Minute>(10)

And there are several interval types available:

Interval<Nanosecond>
Interval<Microsecond>
Interval<Millisecond>
Interval<Second>
Interval<Minute>
Interval<Hour>
Interval<Day>

And those are all different types, it’s almost impossible to confuse them.

The idea behind it is that having these different types contributes to the descriptive quality of your APIs. So, for example, if some function takes Interval<Hour> as a parameter, you can guess that it’s expected to work with time interval of that altitude. Same way, Interval<Nanosecond> means you need very, very small numbers there. Type system helps you give a clear intent to the users of your APIs about what’s expected.

Actually, let’s use an example here.

Imagine you have a function that shows a reminder to a user after some time, taking a number of hours as a parameter. With plain Foundation, its declaration would look something like this:

func notifyUser(afterHours hours: Double)

The problem is that Double doesn’t really mean anything here. Type itself doesn’t give a message that you need an amount of hours. So if the user of your code misses that “afterHours” label, he could write something like this:

let interval: TimeInterval = 3 * 60 * 60 // three hours
notifyUser(afterHours: interval) // no error!

And here we are, trying to notify a user after 10800 hours, which is probably not what the developer wanted.

But it gets much better with Time.

func notifyUser(after hours: Interval<Hour>)

See how the type system clearly states that we need the amount of hours here. And the programmer’s mistake from the previous example:

let interval = 3.seconds * 60 * 60 // three hours in Interval<Second>
notifyUser(after: interval) // error!

Will simply not compile, because Interval<Second> and Interval<Hour> are different types! This compile-time error will most likely illuminate the coder and he would write:

let interval = 3.seconds * 60 * 60
notifyUser(after: interval.inHours)

or even better:

notifyUser(after: 3.hours)

Type-safety just rescued our day.

Convenience-friendly

Of course, all the sweet convenience is present in Time:

let interval = 10.minutes - 15.seconds // Interval<Minute>
10.minutes > 500.seconds // true
let fiveMinutesFromNow = Date() + 5.minutes // Date

The idea: generic type as a descriptor

If you look at how Interval is implemented, it’s actually quite simple:

public struct Interval<Unit : TimeUnit> {

public var value: Double

public init(_ value: Double) {
self.value = value
}

}

But wait, what’s that TimeUnit? It’s a protocol with a very small requirement:

public protocol TimeUnit {

static var toTimeIntervalRatio: Double { get }

}

And time units are defined like this:

public enum Minute : TimeUnit {

public static var toTimeIntervalRatio: Double {
return 60
}
}

The idea here is that you can’t create Minute. Minute is simply a description, a rule by which calculations should be made. Minute doesn’t have any value. Interval<Minute> does.

Using types simply as a description or a rule for something is new for me, but it makes so much sense. In my experience, it helps to reduce boilerplate dramatically while also helping with clarity.

Time is not a library every developer would need, but it showcases how Swift strong type system and generics can really improve reliability of one’s code.

The other lesson I’ve learned while developing Time is that in ideal world every type should have a meaning. TimeInterval aka Double doesn’t really have a meaning, it’s just a number. But Interval<Second> does.

If you have any questions about Time (not space-time though) — ask me a question in “Responses” section below, or ping me on Twitter. Or you can also open an issue (or a pull request!) on GitHub:

GitHub - dreymonde/Time: 🕰 Type-safe time calculations in Swift

Thanks for reading!


Introducing Time was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Lightweight persistence in iOS shouldn’t be this hard]]> https://medium.com/anysuggestion/lightweight-persistence-in-ios-shouldnt-be-that-hard-c200677026d2?source=rss----2535f529da4e---4 https://medium.com/p/c200677026d2 Tue, 06 Jun 2017 22:09:59 GMT 2024-07-11T12:06:45.030Z Introducing Shallows — a reusable, easy-to-use caching library

I think you would agree that sometimes in iOS things that should be easy are made hard. Okay, not hard, but cumbersome, unintuitive, and absolutely no fun.

One of the good examples is a lightweight persistence. Maybe you want to save a small amount of user data on disk. Or to cache some information that came from the web. Or even to store images. You know that these things are kinda easy to implement, but you rather not.

Because these things are tricky. You’re going to write a lot of code ( LightweightPersistenceManager, anyone?), and there are a lot of things you can do wrong, and your solution will probably not be that good or that reusable.

That’s not your fault.

It’s just that on iOS, lightweight persistence doesn’t have its own level of abstraction. The system solutions lacks uniformity, flexibility and they tend to expose a lot of implementation details to us, sometimes making the code that depends on it untestable.

The goal of Shallows is to provide that missing level of abstraction.

First, here’s the link to a GitHub repo:

GitHub - dreymonde/Shallows: 🛶 Your lightweight persistence toolbox

And now let’s dive in.

An abstraction

Meet Storage<Key, Value> — your main friend in a world of lightweight persistence with Shallows.

Storage instances are completely abstract — they don’t expose any implementation detail apart from the types of keys and values. Storages can perform “retrieve” and “set” operations, which are both fallible and asynchronous. Let’s take a look at them:

storage.retrieve(forKey: "batman") { (result) in
switch result {
case .success(let value):
// do something with a value
case .failure(let error):
// handle an error
}
}
storage.set(gordonImage, forKey: "gordon") { (result) in
if result.isSuccess {
// successful set
}
}

How can we get a Storage instance? Storage objects are type-erased, they don’t actually contain any logic. But Shallows provide these storages out of the box:

  1. MemoryStorage<Key: Hashable, Value>
  2. NSCacheStorage<Key: NSObject, Value: AnyObject>
  3. DiskStorage, which is a Storage<Filename, Data>

The last one is probably the most interesting. It is, in fact, our lightweight storage solution. Making one is a straightforward task:

let diskStorage = DiskStorage.folder("json-cache", in: .cachesDirectory)

But it’s just a storage with Data value, why is it interesting to us? Because the coolest thing about Storage is that its representation can be transformed in a way you need. So, for example, we can create a storage of JSON objects:

let jsonStorage = diskStorage.mapJSONDictionary() // Storage<Filename, [String : Any]>

Or use the magic of Swift 4 Codable:

struct Mail: Codable {
let text: String
let address: String
}
let mailDiskStorage = diskStorage.mapJSONObject(Mail.self) // Storage<Filename, Mail>

.mapJSONDictionary and .mapJSONObject are extensions of storage objects with Data value (as also a bunch of others), but we can also perform our custom transformations. For example, let’s create a disk image cache:

let diskStorage = DiskStorage.folder("image-cache", in: .cachesDirectory)
let imagesCache = diskStorage.mapValues(transformIn: { try UIImage(data: $0).unwrap() }, transformOut: { try UIImageJPEGRepresentation($0, 1.0).unwrap() }) // Storage<Filename, UIImage>

Now we have a completely functional disk cache of images. Did you notice how simple, and yet transparent that was? You control everything — you know exactly where your images will be stored and how, and yet it’s that easy. In fact, let’s extract our transformation to an extension, so it can be reused:

extension StorageProtocol where Value == Data {

func mapImages() -> Storage<Key, UIImage> {
return self.mapValues(transformIn: { try UIImage(data: $0).unwrap() }, transformOut: { try UIImageJPEGRepresentation($0, 1.0).unwrap() })
}

}

Now we have a ridiculously simple setup:

let imagesCache = DiskStorage.folder("image-cache", in: .cachesDirectory).mapImages()

And that’s it! Now with a single line of code we can create a disk-based image cache anywhere in our program. And in the end we get a Storage<String, UIImage> instance — completely abstract.

Next step

Shallows, despite being a really compact library, has a lot of powerful features. Probably, one of the best is storage composition.

The image cache we made above is not the most efficient one, because it’s gonna hit the disk every time we request an image. So wouldn’t it be nice to cache already retrieved images to memory? This logic, which could be a nightmare to implement yourself, is provided by Shallows with just a couple of lines of code:

let memoryCache = MemoryStorage<String, UIImage>()
let combinedCache = memoryCache.combined(with: imagesCache)

So now we have a two-layered (memory and disk) image cache. And, again, you’re in a full control of how your layers interact. Many caching libraries hides this from you — they make you completely ignorant about how it works, where it puts the files and so on. But Shallows lets you express your logic clearly, while still being super easy to use.

For now, you just saw how easy it is to create a lightweight storage, and how to make it fast and efficient. We will explore some other cool features and use-cases in upcoming posts, so stay tuned!

If you have any questions about Shallows (or about anything else) — ask me a question in “Responses” section below, or ping me on Twitter. Or you can also open an issue (or a pull request!) on GitHub:

GitHub - dreymonde/Shallows: 🛶 Your lightweight persistence toolbox

As always, thanks for reading!

Hi! I’m Oleg, the author of Women’s Football 2017 and an independent iOS/watchOS developer with a huge passion for Swift. While I’m in the process of delivering my next app, you can check out my last project called “The Cleaning App” — a small utility that will help you track your cleaning routines. Thanks for your support!


Lightweight persistence in iOS shouldn’t be this hard was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[How to use custom type as a key for NSCache]]> https://medium.com/anysuggestion/how-to-use-custom-type-as-a-key-for-nscache-9bdbee02a8f1?source=rss----2535f529da4e---4 https://medium.com/p/9bdbee02a8f1 Tue, 18 Apr 2017 19:20:16 GMT 2017-04-18T19:20:15.694Z NSCache is an amazing Cocoa API which is often overlooked by the developers. NSHipster has an amazing article on it, so I’ll go straight to business.

In Swift 3, NSCache is a generic type. But it doesn’t work as a regular Dictionary. In Dictionary, any Hashable type (including value types, of course) can be used as keys. But NSCache has a strange KeyType : AnyObject constraint, which means that you cannot use value types as a key (which is understandable — NSCache comes from Cocoa).

If you’re using String or IndexPath as a key, things are okay — you should just bridge those to NSString / NSIndexPath. However, using your custom type as a key can be quite tricky.

This custom type of course should be hashable, although the docs and the API itself is silent about it. But if you expect any Hashable class to work with NSCache, you’re wrong. Instead, you should subclass NSObject and override isEqual(_:) and hash. So your code should look like this:

final class CustomKey : NSObject {

let int: Int
let string: String

init(int: Int, string: String) {
self.int = int
self.string = string
}

override func isEqual(_ object: Any?) -> Bool {
guard let other = object as? CustomKey else {
return false
}
return int == other.int && string == other.string
}

override var hash: Int {
return int.hashValue ^ string.hashValue
}

}

Now you can create and use your shiny new NSCache:

let cache = NSCache<CustomKey, UIImage>()

Thanks for reading the post! Don’t hesitate to ask or suggest anything in the “responses” section below. You can also contact me on Twitter.


How to use custom type as a key for NSCache was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Introducing Placeholders]]> https://medium.com/anysuggestion/introducing-placeholders-1cc6927b097d?source=rss----2535f529da4e---4 https://medium.com/p/1cc6927b097d Mon, 17 Apr 2017 14:08:54 GMT 2018-01-19T09:47:08.336Z Set and animate multiple placeholders on UITextField

Placeholder is a powerful concept with a long history — it’s easily recognizable by users, has a strict, reasonable meaning and gives the developer an easy way to hint their users.

Sometimes, however, having just one placeholder is not enough. Sometimes you want to demonstrate your user all the variety of the content that can be entered. For example, if you have a field named “Activity Title”, you can, of course, just put “Running” there as a placeholder. Or you can define a set of placeholders — for example, “Running”, “Walking”, “Rowing”, “Boxing” — and animate them. If this technique is used carefully, it can provide a great user experience. It looks like this:

Basic “push from bottom” transition

Placeholders library allows you just that. Actually, it’s really really simple, and I encourage you to try to implement something like this yourself — it could become a good introduction into iterators, CATransition and Timer (formerly NSTimer). In this article, we’re going to take a quick look at the API, and then we’re going to discuss some architectural choices and features.

Before we begin, here’s the Placeholders on GitHub:

dreymonde/Placeholders

Now let’s dive right in!

How to use

Placeholders was designed to work nicely with view controllers. The central piece of the API is a Placeholders class. You create it in a straightforward manner:

let placeholders = Placeholders(placeholders: ["Running", "Walking", "Biking"])

This will create a set of three placeholders. Of course, often you want to “loop” your placeholders, so that the animation runs forever. Or you want to shuffle your set, so that users don’t see the same placeholders in the same order every time. For that, you should use .infinite and .shuffled options, respectively, like this:

let placeholders = Placeholders(placeholders: ["Running", "Walking", "Biking"], options: [.infinite, .shuffle])

And then, in the viewWillAppear method you should bind the Placeholder instance to your UITextField. You do that by calling start method:

placeholders.start(interval: 3.0,
fireInitial: true,
textField: textField,
animation: .pushTransition(.fromBottom))

(fireInitial is used to set the first placeholder instantly)

And that’s basically it! Now you have multiple animated placeholders. You can play with an interval or tune your animation to fit your needs. If you want to create a completely customized animation, check out the README.

How it works

Overall, the solution is pretty simple: it’s a combination of Timer, iterators and CATransition. The data source is provided via AnyIterator, the placeholder changes are scheduled with Timer and performed with simple CATransition.

If you want to know how the animation is performed, here it is:

let transition = CATransition()
transition.duration = 0.35
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionPush
transition.subtype = kCATransitionFromBottom
textField.subviews.first(where: { NSStringFromClass(type(of: $0)) == "UITextFieldLabel" })?.layer.add(transition, forKey: nil)
textField.placeholder = nextPlaceholder

(Disclaimer: that’s not the code directly from the library — the actual code is split into several functions, but for the sake of simplicity I put it all in one place here.)

How it was made

While developing Placeholder, there were a couple of interesting architectural decisions to make. I want to share some of these in this article.

1. Composition instead of inheritance

Often this kind of added functionality is done via subclassing. Of course, it is possible to simply create MultiplePlaceholdersTextField class and to add some nicely-looking setPlaceholders method to it. But, however, it makes all your custom subclasses of UITextField unusable (or, what’s more likely, you simply won’t use this library). It also decreases the reusability of the code and, overall, is a shady architectural decision: this logic simply doesn’t belong to the View layer.

So that’s why Placeholders is a separate object, which is located in a Controller layer (where, as I believe, it belongs) and can be used with any UITextField, so it’s easy to integrate even with existing codebases.

2. Isolated implementation

If you look at the Placeholder class, you’ll see that it knows absolutely nothing about UITextField (it doesn’t even import UIKit). And all the UITextField functionality is put in an extension, which enables an unprecedented level of customization. Basically, you can customize the process almost at every step.

The Placeholder object itself has only one start method:

func start(interval: TimeInterval, fireInitial: Bool, action: @escaping (Element) -> ())

And the method for UITextField which is described in the usage section is just a wrapper around it. That efficiently separates the logic, making the actual implementation simpler and more manageable.

You can read more about the idea behind this approach here.

3. Iterator instead of array

Under the hood, Placeholders uses AnyIterator instead of a simple array. This is made for two reasons:

  1. Having iterator is enough. We don’t need the fully equiped array here. We just need something that will give us the next element each time. Iterator is actually that “something”.
  2. Iterators can be modified in interesting ways. For example, the “infinite” functionality works on an iterator level, it’s not something that’s embedded into Placeholders. You can check out the implementation of InfiniteIterator here.

4. Generics

You may have not noticed it, but Placeholders is actually a generic type. Why is that? Because this way you can use both String and NSAttributedString with an identical syntax!

Well, that’s the Placeholders. It’s a small and simple library, but it was fun and interesting to write. If you have any questions about it (or about anything else) — ask me a question in “Responses” section below, or ping me on Twitter. Or you can also open an issue (or a pull request!) on GitHub:

dreymonde/Placeholders

Thank you for reading!


Introducing Placeholders was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>
<![CDATA[Postponing internationalization without feeling guilty]]> https://medium.com/anysuggestion/swift-snippet-how-to-postpone-internationalization-without-feeling-guilty-cf82c1e33f7a?source=rss----2535f529da4e---4 https://medium.com/p/cf82c1e33f7a Thu, 23 Mar 2017 20:25:16 GMT 2018-01-19T09:49:47.246Z Being lazy isn’t shameful when you’re conscious about it

We all know that we should start to care about internationalization very early in the iOS development cycle. However, when your specification is changing rapidly or you’re experimenting a lot, switching between your code and Localizable.strings often can be quite distracting. On the other hand, if you don’t care about internationalization at all and just throw unlocalized strings straight to the UI, you’re going to encounter serious problems later.

So I propose a simple and elegant solution. Here it is:

extension String {

#if DEBUG
var unlocalized: String {
return self
}
#else
@available(*, deprecated, message: "You should not use unlocalized strings in release builds")
var unlocalized: String {
return self
}
#endif

}

And then, when we pass unlocalized strings to the UI, we simply mark them as such:

label.text = "The \(fruit.name) contains \(fruit.calories) calories".unlocalized

So what’s the deal with that? First, finding all unlocalized strings is a trivial task now (just search for “unlocalized” keyword). But more than that, now the compiler will warn us at every place where we use such strings when we switch to “Release” mode (of course you can adjust that logic however you want). The warnings looks like that:

Of course, you still have to remember to write those .unlocalized all over the place. So you still should care about internationalization early. And I never said you shouldn’t. But by writing .unlocalized , you’re making a conscious and intentional statement:

Yes, I know that I’m doing things wrong, and I will certainly fix them later — I just don’t want to lose my momentum right now.

And it’s great. You’re not just ignoring internationalization. You’re aware of it. You know how important that is. And you will do everything right, but just not right now. You’re postponing it.

So keep that momentum going.

Thanks for reading the post! Don’t hesitate to ask or suggest anything in the “responses” section below. You can also contact me on Twitter.


Postponing internationalization without feeling guilty was originally published in AnySuggestion on Medium, where people are continuing the conversation by highlighting and responding to this story.

]]>