All posts
Post
Actors eliminate data races, not retain cycles. If your actor stores a Task whose body captures self, you just built a memory leak that won’t crash — it will quietly persist.
- Keep cancellation close to creation: only store a
Taskwhen you must callcancel()across scopes; otherwise make it local and let scope exit drop it. - Prefer
AsyncStreamfor repeating push sources; setcontinuation.onTerminationand expose astop()that finishes the stream and removesNotificationCenterobservers. - Use
nonisolatedonly for methods that truly don’t touch actor state; bounce back into the actor withawait self.method()when mutation is required. - Bridge legacy callbacks with
withCheckedThrowingContinuationand avoid capturing the actor; resume exactly once to prevent pinning tasks. - Validate lifecycle: add
deinitthat cancels timers/loops (Task.sleep) and nils stored closures; assert deallocation inXCTest.
Choose a stored Task only when you require cross‑scope cancellation; otherwise keep work local to avoid owning lifetimes you can’t reliably terminate.
Trace with OSSignposter and Instruments, and monitor field behavior