Recent articles

Jump to a random post

What’s new with UICollectionView in iOS 14

Published on: June 25, 2020

Last year, the team that works on UICollectionView shipped massive improvements like compositional layout and diffable data sources. This year, the team went all out and shipped even more amazing improvements to UICollectionView, making UITableView obsolete through the new UICollectionViewCompositionalLayout.list and UICollectionLayoutListConfiguration. This new list layout allows you to create collection views that look and function identical to UITableView. When paired with UICollectionViewListCell your collection view can support features that used to only be available to UITableView. For instance, you can now add swipe actions to a cell and set its accessories to add certain affordances on a cell like...

Read more...

How to add a custom accessory to a UICollectionViewListCell?

Published on: June 24, 2020

Apple provides several accessory types that you can use to apply certain affordances to a UICollectionViewListCell. However, sometimes these options don't suit your needs and you're looking for something more customizable. To add a custom accessory to a list cell instead of a standard one, you use the .custom accessory type. The initializer for this accessory takes a UICellAccessory.CustomViewConfiguration that describes how your accessory should look and where it's positioned. Let's dive right in with an example: // create the accessory configuration let customAccessory = UICellAccessory.CustomViewConfiguration( customView: UIImageView(image: UIImage(systemName: "paperplane")), placement: .leading(displayed: .always)) // add the accessory to the cell...

Read more...

How to add accessories to a UICollectionViewListCell?

Published on: June 24, 2020

In iOS 14 Apple added the ability for developers to create collection views that look and feel like table views, except they are far, far more powerful. To do this, Apple introduced a new UICollectionViewCell subclass called UICollectionViewListCell. This new cell class allows us to implement several tableviewcell-like principles, including accessories. Adding accessories to a cell is done by assigning an array of UICellAccessory items to a UICollectionViewListCell's accessories property. For example, to make a UICollectionViewListCell show a disclosure indicator that makes it clear to a user that they will see more content if they tapp a cell, you would...

Read more...

How to add custom swipe actions to a UICollectionViewListCell?

Published on: June 24, 2020

In iOS 14 Apple added the ability for developers to create collection views that look and feel like table views, except they are far, far more powerful. To do this, Apple introduced a new UICollectionViewCell subclass called UICollectionViewListCell. This new cell class allows us to implement several tableviewcell-like principles, including swipe actions. You can add both leading and trailing swipe actions to a cell by assigning a UISwipeActionsConfigurationProvider instance to the collection view's UICollectionLayoutListConfiguration object's leadingSwipeActionsConfigurationProvider and trailingSwipeActionsConfigurationProvider properties. This swipe actions provider is expected to return an instance of UISwipeActionsConfiguration. A UISwipeActionsConfiguration is created using an array of one...

Read more...

Configure collection view cells with UICollectionView.CellRegistration

Published on: June 24, 2020

In iOS 14 you can use the new UICollectionView.CellRegistration class to register and configure your UICollectionViewCell instances. So no more let cellIdentifier = "MyCell", no more collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) and best of all, you no longer need to cast the cell returned by dequeueReusableCell(withReuseIdentifier:for:) to your custom cell class. Adopting UICollectionView.CellRegistration in your project is surprisingly straightforward. For demo purposes I created the following UICollectionViewCell subclass: class MyCollectionViewCell: UICollectionViewCell { let label = UILabel() required init?(coder: NSCoder) { fatalError("nope!") } override init(frame: CGRect) { super.init(frame: frame) contentView.addSubview(label) label.translatesAutoresizingMaskIntoConstraints = false label.topAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.topAnchor, constant: 8).isActive = true label.leadingAnchor.constraint(equalTo: contentView.safeAreaLayoutGuide.leadingAnchor, constant:...

Read more...

What’s the difference between @StateObject and @ObservedObject?

Published on: June 23, 2020

Views in SwiftUI are thrown away and recreated regularly. When this happens, the entire view struct is initialized all over again. Because of this, any values that you create in a SwiftUI view are reset to their default values unless you've marked these values using @State. This means that if you declare a view that creates its own @ObservedObject instance, that instance is replaced every time SwiftUI decides that it needs to discard and redraw that view. If you want to see what I mean, try running the following SwiftUI view: class DataSource: ObservableObject { @Published var counter = 0...

Read more...

Using custom publishers to drive SwiftUI views

Published on: June 23, 2020

In SwiftUI, views can be driven by an @Published property that's part of an ObservableObject. If you've used SwiftUI and @Published before, following code should look somewhat familiar to you: class DataSource: ObservableObject { @Published var names = [String]() } struct NamesList: View { @ObservedObject var dataSource: DataSource var body: some View { List(dataSource.names, id: \.self) { name in Text(name) } } } Whenever the DataSource object's names array changes, NamesList will be automatically redrawn. That's great. Now imagine that our list of names is retrieved through the network somehow and we want to load the list of names in...

Read more...

Ignore first number of elements from a publisher in Combine

Published on: June 19, 2020

If you have a Combine publisher and you want to ignore the first n elements that are published by that publisher, you can use the dropFirst(_:) operator. This operator will swallow any values emitted until the threshold you specify is reached. For example, dropFirst(1) will ignore the first emitted value from a publisher: [1, 2, 3].publisher .dropFirst(1) .sink(receiveValue: { value in print(value) // 2 and 3 are printed }) For more information about dropFirst and several variations of drop like drop(while:) and drop(untilOutputFrom:) you can refer to Apple's documentation.

Read more...

Recursively execute a paginated network call with Combine

Published on: June 15, 2020

Last week, my attention was caught by a question that Dennis Parussini asked on Twitter. Dennis wanted to recursively make calls to a paginated API to load all pages of data before rendering UI. Since I love Combine and interesting problems I immediately started thinking about ways to achieve this using a nice, clean API. And then I realized that this is a non-trivial task that was worth exploring. In this week's post, I would like to share my thought process and solution with you, hoping you'll learn something new about Combine in the process. Understanding the problem and setting...

Read more...

What’s the difference between Float and Double in Swift

Published on: June 10, 2020

A Double and Float are both used to represent decimal numbers, but they do so in slightly different ways. If you initialize a decimal number in Swift using as shown below, the Swift compiler will assume that you meant to create a Double: let val = 3.123 // val is inferred to be Double The reason for this is that Double is the more precise type when comparing it to Float. A Float holds a total of 8 positions, or 32 bits. Since Double is more precise, it can hold more positions. It uses 64 bits to do this. In...

Read more...