SoFunction
Updated on 2025-04-12

Summary of four callback methods for iOS

Recently, I encountered a callback for IOS projects, so I took the time to sort out the relevant information. The following is the sorting content:

Callback

A callback is to bind an executable piece of code to a specific event. This code is executed when a specific event occurs.
In Objective-C, there are four ways to implement callbacks.

Target-action pair

Before the program starts to wait, it is required that "when time occurs, send a specific information to the specified object." Here the object that receives the message is the target, and the message selector is the action.

Auxiliary object

Before the program starts waiting, it is required to "send a message to the auxiliary object that complies with the corresponding protocol when time occurs." Delegate objects and data sources are common helper objects.

notify

Apple provides an object called Notification Center. Before the program starts waiting, you can inform the notification center that "an object is waiting for certain specific notifications. When one of the notifications appears, a specific message is sent to the specified object." When an event occurs, the relevant object will issue a notification to the Notification Center, and the Notification Center will forward the notification to the object waiting for the notification.

Block object

Block is a piece of executable code. Before the program starts waiting, declare a Block object, and execute this Block object when the event occurs.

NSRunLoop

There is an NSRunLoop class in iOS. The NSRunLoop instance will continue to wait. When a specific event occurs, a message will be sent to the corresponding object. An NSRunLoop instance triggers a callback when a specific event occurs.

cycle

Before implementing a callback, you need to create a loop:

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    [[NSRunLoop currentRunLoop]run];
  }
  return 0;
}

Target-action pair

Create an application with NSRunLoop objects and NSTimer objects. Every two seconds, the NSTimer object will send the specified action message to its target, creating a new class named BNRLogger, which is the target of the NSTimer object.
Declare the action method in:

#import <Foundation/>

@interface BNRLogger : NSObject<NSURLSessionDataDelegate>
@property(nonatomic) NSDate *lastTime;

-(NSString *) lastTimeString;
-(void)updateLastTime: (NSTimer *) t;

@end

Implementation method in:

#import ""

@implementation BNRLogger

-(NSString *)lastTimeString
{
  static NSDateFormatter *dateFormatter=nil;

  if(!dateFormatter)
  {
    dateFormatter =[[NSDateFormatter alloc]init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];

    NSLog(@"created dateFormatter");
  }
  return [dateFormatter stringFromDate:];
}

-(void)updateLastTime:(NSTimer *)t
{
  NSDate *now=[NSDate date];
  [self setLastTime:now];
  NSLog(@"Just set time to %@",);
}

@end

Create a BNRLogger instance in:

#import <Foundation/>
#import ""

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    BNRLogger *logger=[[BNRLogger alloc]init];

    __unused NSTimer *timer=[NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(updateLastTime:) userInfo:nil repeats:YES];

    [[NSRunLoop currentRunLoop]run];
  }
  return 0;
}


Auxiliary object

My previous blog has written about the use of the NSURLSession method, so the use of the helper object callback will turn the BNRLogger object into the delegate object of the NSURLSession. When a specific event occurs, the object will send a message to the helper object.
Create an NSURL object and an NSURLRequest object in it. Then create an NSURLSession object and set the instance of BNRLogger to its

Delegation object:

#import &lt;Foundation/&gt;
#import ""

int main(int argc, const char * argv[]) {
  @autoreleasepool {
    BNRLogger *logger=[[BNRLogger alloc]init];

    //The URL is a download link for an image    NSURL *url = [NSURL URLWithString:@"/search/down?tn=download&amp;ipn=dwnl&amp;word=download&amp;ie=utf8&amp;fr=result&amp;url=http%3A%2F%%2Fuploads%2F2016%2F0914%&amp;thumburl=http%3A%2F%%2Fit%2Fu%3D2349180720%2C2436282788%26fm%3D11%26gp%"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    __unused NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:logger delegateQueue:[NSOperationQueue mainQueue]];

    __unused NSTimer *timer=[NSTimer scheduledTimerWithTimeInterval:2.0 target:logger selector:@selector(updateLastTime:) userInfo:nil repeats:YES];

    //4. Create a Task based on the session object (send a request)    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request];

    //5. Execute tasks    [dataTask resume];

    [[NSRunLoop currentRunLoop]run];

  }
  return 0;
}

In, declare the NSURLSessionDataDelegate protocol:

#import <Foundation/>

@interface BNRLogger : NSObject<NSURLSessionDataDelegate>
@property (nonatomic, strong) NSMutableData *responseData;
@property(nonatomic) NSDate *lastTime;

-(NSString *) lastTimeString;
-(void)updateLastTime: (NSTimer *) t;

@end

There is the proxy method of NSURLSession. For details, you can see NSURLSession:

#import ""

@implementation BNRLogger

-(NSMutableData *)responseData
{
  if (_responseData == nil) {
    _responseData = [NSMutableData data];
  }
  return _responseData;
}

-(NSString *)lastTimeString
{
  static NSDateFormatter *dateFormatter=nil;

  if(!dateFormatter)
  {
    dateFormatter =[[NSDateFormatter alloc]init];
    [dateFormatter setTimeStyle:NSDateFormatterMediumStyle];
    [dateFormatter setDateStyle:NSDateFormatterMediumStyle];

    NSLog(@"created dateFormatter");
  }
  return [dateFormatter stringFromDate:];
}

-(void)updateLastTime:(NSTimer *)t
{
  NSDate *now=[NSDate date];
  [self setLastTime:now];
  NSLog(@"Just set time to %@",);
}

//1. Call this method when receiving the server response-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
  //In this method, you can get the response header information, that is, the response  NSLog(@"didReceiveResponse--%@",[NSThread currentThread]);
  NSLog(@"response");
  //Note: You need to use the completionHandler callback to tell the system how to process the data returned by the server.  //Cancel by default  /*
    NSURLSessionResponseCancel = 0, default processing method, cancel
    NSURLSessionResponseAllow = 1, receive data returned by the server
    NSURLSessionResponseBecomeDownload = 2, becomes a download request
    NSURLSessionResponseBecomeStream becomes a stream
    */

  completionHandler(NSURLSessionResponseAllow);
}

//2. This method will be called when receiving the server's return data. If the data is large, the method may be called multiple times.-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
  NSLog(@"didReceiveData--%@",[NSThread currentThread]);
  NSLog(@"return");
  //The data returned by the splicing server  [ appendData:data];
}

//3. This method will be called when the request completes (success|failed). If the request fails, the error has a value-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
  NSLog(@"didCompleteWithError--%@",[NSThread currentThread]);
  NSLog(@"Finish");
  if(error == nil)
  {
    //Analyze the data    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData: options:kNilOptions error:nil];
    NSLog(@"%@",dict);
  }
}

@end

notify

When the system time zone changes, an NSSystemTimeZoneDidChangeNotification notification will be issued to the Notification Center, and the Notification Center will forward the notification to the corresponding observer.

Register the BNRLogger instance as an observer. If the system time zone settings change, you can receive corresponding notifications:

 //Include this line of code in the "Helpful Object" method application [[NSNotificationCenter defaultCenter]addObserver:logger selector:@selector(zoneChange:) name:NSSystemTimeZoneDidChangeNotification object:nil];

Implement this method in:

 //Include this line of code in the "Helpful Object" method application -(void)zoneChange:(NSNotification *)note
{
  NSLog(@"The system time zone has changed!");
}

Block callback

Put the "notification" method mentioned above in the application:

[[NSNotificationCenter defaultCenter]addObserver:logger selector:@selector(zoneChange:) name:NSSystemTimeZoneDidChangeNotification object:nil];

Change to:

[[NSNotificationCenter defaultCenter]addObserverForName:NSSystemTimeZoneDidChangeNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note){
      NSLog(@"The system time zone has changed!");
    }];

Remove this method from the "notification" method application:

-(void)zoneChange:(NSNotification *)note
{
  NSLog(@"The system time zone has changed!");
}

Summarize

  1. For objects that do only one thing (for example), use the target-action pair.
  2. For more complex objects (such as NSURLSession), use helper objects. The most common type of helper object is the delegate object.
  3. For objects (such as NSTimeZone) that want to trigger multiple (in other objects) callbacks, use notifications.
  4. Block implements callbacks to make the code easy to read.

Thank you for reading, I hope it can help you. Thank you for your support for this site!