Mobile Development 10 min read

Understanding iOS RunLoop: Concepts, Functions, and Practical Applications

This article explains the iOS RunLoop mechanism, its role in keeping apps responsive, how it interacts with UIApplicationMain, timers, thread management, and various RunLoop modes, and provides practical examples for using RunLoop to maintain thread life cycles and improve UI performance.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Understanding iOS RunLoop: Concepts, Functions, and Practical Applications

Every iOS app relies on a RunLoop to stay alive and respond to user interactions; without it, an app would become idle after launch. The RunLoop is a low‑level event‑processing loop that continuously waits for input sources, timers, and observers.

The entry point of an iOS program is int UIApplicationMain(int argc, char * _Nullable *argv, NSString *principalClassName, NSString *delegateClassName); , which creates the application object, its delegate, and sets up the main thread’s RunLoop, ensuring the app never exits.

RunLoop’s primary responsibilities are to keep the thread alive and to monitor all events such as clock events, selector events, and touch events. It processes events in different modes; the most common are NSDefaultRunLoopMode , UITrackingRunLoopMode , and NSRunLoopCommonModes . When a timer is added to a RunLoop in the default mode, it will not fire while the UI is being scrolled because the RunLoop switches to UITrackingRunLoopMode . Using NSRunLoopCommonModes makes the timer fire in both modes.

Timers can be created with two APIs:

+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;

and

+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;

The first requires manually adding the timer to a RunLoop via addTimer:forMode: , while the second automatically schedules the timer on the current RunLoop.

RunLoop objects cannot be instantiated directly; they are obtained through:

CFRunLoopGetCurrent(); and CFRunLoopGetMain(); for Core Foundation, or [NSRunLoop currentRunLoop]; and [NSRunLoop mainRunLoop]; for Foundation.

Core Foundation defines five related classes: CFRunLoopRef , CFRunLoopModeRef , CFRunLoopSourceRef , CFRunLoopObserverRef , and CFRunLoopTimerRef . A RunLoop contains multiple modes, each composed of sources (event inputs), timers, and observers.

Sources represent all event origins; they can be port‑based, custom, or Cocoa selector sources. Timers correspond to NSTimer objects, and observers monitor RunLoop state changes such as kCFRunLoopBeforeSources or kCFRunLoopAfterWaiting .

Each thread has a unique RunLoop. The main thread’s RunLoop is created by the system, while a child thread’s RunLoop is created on first access and must be kept alive manually. By adding an NSTimer to a background thread’s RunLoop and running the loop, the thread remains active and can process periodic tasks.

RunLoop can also be used to off‑load heavy operations from the main thread. By adding a CFRunLoopObserverRef that executes a single time‑consuming task each loop iteration, UI lag is reduced.

In summary, RunLoop is essential for keeping iOS apps responsive, managing timers, handling multiple event modes, and preserving thread life cycles, making it a powerful tool for performance optimization.

Mobile DevelopmentiOSRunLoopThread ManagementEvent LoopNSTimer
JD Retail Technology
Written by

JD Retail Technology

Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.