When building an app, you may need to create thousands or tens of thousands of similar objects. A typical example is placing tens of thousands of markers on a map, where the memory graph can easily keep climbing.
This is where the Flyweight Pattern can help. In short, it combines and shares data used by multiple objects to greatly reduce memory usage. Instead of creating the same thing repeatedly, create it once and reuse it.
This article explains what the Flyweight Pattern is in Swift, when to use it, and how to implement it with real code.
What exactly is the Flyweight Pattern?
Flyweight means a “lightweight object.” It is also the name of the lightest weight class in boxing.
The idea is simple: divide an object’s data into two types.
- Intrinsic state: immutable data that multiple objects can share, such as a tree species, texture, or color.
- Extrinsic state: data that differs between objects and changes over time, such as a tree’s position or size.
Imagine drawing a forest. What if you need to draw one million trees, but they are really only three species: pine, oak, and maple?
Create and share only three sets of texture and color information (intrinsic state), while storing one million position values (extrinsic state) separately.
Create and share heavy common data once, and manage only lightweight individual data separately. That is the entire Flyweight Pattern.
Let’s implement it in Swift
It’s hard to get a feel for it from words alone, so let’s look at the code. We’ll translate the tree example from earlier directly.
First, here is the Flyweight object that stores the intrinsic state to share.
// Shared heavy data (intrinsic state)
final class TreeType {
let name: String
let color: String
let texture: Data // Large texture
init(name: String, color: String, texture: Data) {
self.name = name
self.color = color
self.texture = texture
}
}
Next, we create a factory that manages and shares these TreeTypes. If a type has already been created, it reuses it instead of creating another one.
// Reuse the same type instead of creating it again
final class TreeFactory {
private var pool: [String: TreeType] = [:]
func treeType(name: String, color: String, texture: Data) -> TreeType {
let key = "\(name)-\(color)"
if let existing = pool[key] { return existing }
let type = TreeType(name: name, color: color, texture: texture)
pool[key] = type
return type
}
}
The actual tree now stores only extrinsic state such as its position, and merely references the heavy data through TreeType.
// Each tree stores only its position and shares its type by reference
struct Tree {
let x: Double
let y: Double
let type: TreeType // Reference to the shared object
}
Even with one million trees, there are only as many TreeType instances as species—for example, three. Everything else is simply a reference to one of those three.
When to use it—and when not to
The Flyweight Pattern is not always the right answer. In many cases, avoiding it is better. Here’s a summary by situation.
| Situation | Flyweight |
|---|---|
| Creating very large numbers of similar objects | Suitable |
| Objects contain heavy data that can be shared | Suitable |
| Few objects | Unnecessary (only increases complexity) |
| Most state differs from object to object | Minimal benefit |
The Flyweight Pattern is a good fit when both conditions overlap: many objects and heavy data that can be shared.
In Swift, class is already shared by reference because it is a reference type, so the pattern is especially effective when heavy data is embedded in value-type structs and copied repeatedly.
Frequently asked questions
Q. How is it different from the Singleton Pattern?
Singleton forces a class to have exactly one instance. Flyweight allows multiple instances, but shares only what can be shared—for example, three tree types and one million trees.
Q. I keep confusing it with caching.
The goals differ. Caching stores results so you do not have to calculate or retrieve them again, while Flyweight manages shared objects to save memory. The factory’s pool does behave somewhat like a cache, though.
Q. Is it used in the Swift Standard Library too?
Yes. String interning and small-integer caching are representative optimizations based on a similar idea: share identical values instead of creating them repeatedly.
The Flyweight Pattern sounds complicated, but the idea is very simple: “Create overlapping heavy data once and share it.”
If you need to handle large numbers of similar objects—map markers, particles, tile maps, or text rendering—keep it in mind. You may find that the memory graph becomes noticeably calmer.

