iOS development
dismissModalViewController
data passing
mobile app development
Objective-C

dismissModalViewController AND pass data back

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Passing data back while dismissing a modal view controller is a standard iOS workflow for forms and pickers. Older code used dismissModalViewControllerAnimated, but modern UIKit uses dismissViewControllerAnimated:completion:. The important part is not dismissal itself, it is choosing a clear channel for returning values to the presenting controller.

Modern Dismissal Pattern In UIKit

If the presented controller needs to return one value, a delegate is usually the most explicit pattern in Objective C. The child view controller informs the parent through a protocol method, and the parent decides what to do with the result.

objectivec
1// EditNameViewController.h
2#import <UIKit/UIKit.h>
3
4@class EditNameViewController;
5
6@protocol EditNameViewControllerDelegate <NSObject>
7- (void)editNameViewController:(EditNameViewController *)controller
8               didSaveName:(NSString *)name;
9@end
10
11@interface EditNameViewController : UIViewController
12@property (nonatomic, weak) id<EditNameViewControllerDelegate> delegate;
13@end
objectivec
1// EditNameViewController.m
2#import "EditNameViewController.h"
3
4@implementation EditNameViewController
5
6- (void)saveTapped {
7    NSString *newName = @"Jordan";
8    [self.delegate editNameViewController:self didSaveName:newName];
9    [self dismissViewControllerAnimated:YES completion:nil];
10}
11
12@end

The parent sets itself as delegate before presenting.

Parent Controller Integration

objectivec
1// ProfileViewController.m
2#import "ProfileViewController.h"
3#import "EditNameViewController.h"
4
5@interface ProfileViewController () <EditNameViewControllerDelegate>
6@property (nonatomic, strong) NSString *displayName;
7@end
8
9@implementation ProfileViewController
10
11- (void)presentEditor {
12    EditNameViewController *vc = [[EditNameViewController alloc] init];
13    vc.delegate = self;
14    [self presentViewController:vc animated:YES completion:nil];
15}
16
17- (void)editNameViewController:(EditNameViewController *)controller
18                   didSaveName:(NSString *)name {
19    self.displayName = name;
20}
21
22@end

This avoids global notifications and keeps ownership explicit.

When To Use Completion Blocks Or Notifications

For one off interactions, a completion block property is lightweight and easy to follow. For app wide events, notification center can work, but it is less explicit and harder to refactor safely.

A practical rule:

  • Delegate for structured one to one communication.
  • Completion block for simple callback payloads.
  • Notification center only for broad broadcast style events.

Also ensure dismissal happens on the main thread. UIKit updates are not thread safe, and background thread dismissal can cause inconsistent transitions.

Migration Note For Legacy APIs

If you maintain older code, replace dismissModalViewControllerAnimated with dismissViewControllerAnimated:completion:. The old API is deprecated and should not be used in modern iOS targets. Migration is usually mechanical, but review data flow at the same time so you do not carry forward brittle patterns.

Testing And Reliability Checklist

Modal flows should be covered by UI tests because timing issues are easy to miss in manual checks. Validate the full round trip: present modal, enter value, save, dismiss, and assert the parent state changed. Add a cancel path test as well so dismiss without save does not overwrite existing data.

Memory behavior matters too. If you choose block callbacks, confirm the modal does not retain the parent strongly. A weak capture for controller references is often required to avoid leaks. Instruments can verify deallocation after dismissal.

Finally, keep transition and data code separate. The modal should emit a result through one channel, and the parent should own persistence and UI refresh. This separation improves reuse and makes failures easier to isolate during debugging.

A small naming convention also helps: use didSave, didCancel, and didDelete style delegate methods so callback intent is obvious during reviews.

Common Pitfalls

  • Dismissing before sending data back, causing the parent to miss updates.
  • Using strong references in callbacks and creating retain cycles.
  • Relying on notification center for local one screen interactions.
  • Updating presenting controller UI before data state is actually changed.
  • Mixing several return channels in one flow, which makes behavior unpredictable.

Summary

  • Use modern UIKit dismissal APIs for modal flows.
  • Return data with delegates for clear controller boundaries.
  • Keep data handoff explicit before or during dismissal.
  • Prefer one communication pattern per interaction.
  • Audit legacy modal code for deprecated API usage and weak ownership bugs.

Course illustration
Course illustration

All Rights Reserved.