Objective-C ARC Patterns
Use when automatic Reference Counting in Objective-C including strong/weak references, retain cycles, ownership qualifiers, bridging with Core Foundation, and patterns for memory-safe code without manual retain/release.
What this skill does
# Objective-C ARC Patterns
## Introduction
Automatic Reference Counting (ARC) is Objective-C's memory management system
that automatically inserts retain and release calls at compile time. ARC
eliminates most manual memory management while providing deterministic memory
behavior and preventing common memory bugs like use-after-free and double-free.
Unlike garbage collection, ARC provides immediate deallocation when reference
counts reach zero, making it suitable for resource-constrained environments like
iOS. Understanding ARC's ownership rules, qualifiers, and patterns is essential
for writing memory-safe Objective-C code and avoiding retain cycles.
This skill covers strong and weak references, ownership qualifiers, retain
cycles, Core Foundation bridging, and best practices for ARC-based memory
management.
## Strong and Weak References
Strong references maintain ownership of objects and prevent deallocation, while
weak references observe objects without preventing deallocation.
```objectivec
// Strong references (default)
@interface Person : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *friends;
@property (nonatomic, strong) UIImage *photo;
@end
@implementation Person
@end
// Weak references
@interface ViewController : UIViewController
@property (nonatomic, weak) id<ViewControllerDelegate> delegate;
@property (nonatomic, weak) IBOutlet UILabel *nameLabel;
@end
@implementation ViewController
@end
@protocol ViewControllerDelegate <NSObject>
- (void)viewControllerDidFinish:(ViewController *)controller;
@end
// Using strong and weak
void strongWeakExample(void) {
Person *person = [[Person alloc] init];
person.name = @"Alice"; // Strong reference to NSString
__weak Person *weakPerson = person; // Weak reference
NSLog(@"Weak person: %@", weakPerson.name);
person = nil; // Person deallocated
NSLog(@"After nil: %@", weakPerson); // weakPerson is now nil
}
// Unowned references (unsafe_unretained)
@interface NodeOld : NSObject
@property (nonatomic, unsafe_unretained) NodeOld *parent;
@property (nonatomic, strong) NSArray<NodeOld *> *children;
@end
@implementation NodeOld
@end
// Weak vs unowned
@interface CommentOld : NSObject
@property (nonatomic, strong) NSString *text;
@property (nonatomic, weak) PostOld *post; // Weak: can be nil
@end
@interface PostOld : NSObject
@property (nonatomic, strong) NSArray<CommentOld *> *comments;
@end
@implementation CommentOld
@end
@implementation PostOld
@end
// Strong captures in blocks
void blockCaptureExample(void) {
Person *person = [[Person alloc] init];
person.name = @"Bob";
// Strong capture
void (^strongBlock)(void) = ^{
NSLog(@"%@", person.name); // Captures person strongly
};
// Weak capture to avoid retain cycle
__weak Person *weakPerson = person;
void (^weakBlock)(void) = ^{
NSLog(@"%@", weakPerson.name); // Captures weakly
};
strongBlock();
weakBlock();
}
```
Strong references increment retain count, while weak references are
automatically set to nil when the object deallocates, preventing dangling
pointers.
## Retain Cycles and Breaking Them
Retain cycles occur when objects hold strong references to each other, preventing
deallocation. Breaking cycles requires weak or unowned references.
```objectivec
// Retain cycle example
@interface Parent : NSObject
@property (nonatomic, strong) NSArray<Child *> *children;
@end
@interface Child : NSObject
@property (nonatomic, weak) Parent *parent; // Weak to break cycle
@property (nonatomic, strong) NSString *name;
@end
@implementation Parent
- (void)dealloc {
NSLog(@"Parent deallocated");
}
@end
@implementation Child
- (void)dealloc {
NSLog(@"Child deallocated");
}
@end
void noCycleExample(void) {
Parent *parent = [[Parent alloc] init];
Child *child = [[Child alloc] init];
child.name = @"Alice";
child.parent = parent; // Weak reference
parent.children = @[child]; // Strong reference
// When parent goes out of scope, both deallocate
}
// Delegate pattern without cycles
@protocol DataSourceDelegate <NSObject>
- (void)dataSourceDidUpdate:(id)source;
@end
@interface DataSource : NSObject
@property (nonatomic, weak) id<DataSourceDelegate> delegate;
- (void)fetchData;
@end
@implementation DataSource
- (void)fetchData {
// Fetch data
[self.delegate dataSourceDidUpdate:self];
}
- (void)dealloc {
NSLog(@"DataSource deallocated");
}
@end
// Block retain cycles
@interface NetworkManager : NSObject
@property (nonatomic, strong) NSString *baseURL;
- (void)fetchDataWithCompletion:(void (^)(NSData *data))completion;
@end
@implementation NetworkManager
- (void)fetchDataWithCompletion:(void (^)(NSData *))completion {
// Simulate async work
dispatch_async(dispatch_get_global_queue(
DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *data = [@"response" dataUsingEncoding:NSUTF8StringEncoding];
dispatch_async(dispatch_get_main_queue(), ^{
completion(data);
});
});
}
- (void)dealloc {
NSLog(@"NetworkManager deallocated");
}
@end
// Avoiding block cycles with weak-strong dance
@interface ViewController2 : UIViewController
@property (nonatomic, strong) NetworkManager *networkManager;
@end
@implementation ViewController2
- (void)loadData {
__weak typeof(self) weakSelf = self;
[self.networkManager fetchDataWithCompletion:^(NSData *data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (!strongSelf) return;
// Use strongSelf safely
NSLog(@"Data loaded: %@", strongSelf.view);
}];
}
- (void)dealloc {
NSLog(@"ViewController2 deallocated");
}
@end
// Observer pattern cycles
@interface Observable : NSObject
@property (nonatomic, strong) NSMutableArray *observers;
- (void)addObserver:(id)observer;
- (void)removeObserver:(id)observer;
- (void)notifyObservers;
@end
@implementation Observable
- (instancetype)init {
self = [super init];
if (self) {
_observers = [NSMutableArray array];
}
return self;
}
- (void)addObserver:(id)observer {
// Use NSPointerArray for weak references
[self.observers addObject:[NSValue valueWithPointer:(__bridge void *)observer]];
}
- (void)removeObserver:(id)observer {
[self.observers removeObject:[NSValue valueWithPointer:(__bridge void *)observer]];
}
- (void)notifyObservers {
for (NSValue *value in self.observers) {
id observer = (__bridge id)(void *)[value pointerValue];
if (observer) {
// Notify observer
}
}
}
@end
```
Always use weak references for delegates, parent pointers, and observers to
break retain cycles. Use the weak-strong dance in blocks for safe self access.
## Ownership Qualifiers
ARC provides ownership qualifiers that explicitly control memory management
behavior for variables and properties.
```objectivec
// Property ownership qualifiers
@interface Container : NSObject
// Strong: default for object pointers
@property (nonatomic, strong) id strongProperty;
// Weak: doesn't prevent deallocation
@property (nonatomic, weak) id weakProperty;
// Copy: creates a copy of the object
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSArray *items;
// Assign: for non-object types
@property (nonatomic, assign) NSInteger count;
@property (nonatomic, assign) CGFloat value;
// Unsafe_unretained: weak without nil-ing
@property (nonatomic, unsafe_unretained) id unsafeProperty;
@end
@implementation Container
@end
// Variable qualifiers
void qualifierExamples(void) {
// __strong: default qualifier
__strong NSString *strongString = @"Hello";
// __weak: weak reference
__weak NSString *weakString = strongString;
// __unsafe_unretained: unmanaged weak
__unsafe_unretained NSString *unsafeString = strongString;
// __autoreleasing: for out parameters
NSError * __autoreleasing error;
}
// Copy property beRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.