欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS 四种回调方法总结

程序员文章站 2023-12-18 20:21:52
最近对做ios 项目遇到回调,抽空把相关资料整理下,以下是整理内容: 回调 回调就是将一段可执行的代码和一个特定的事件绑定起来。当特定的事件发生时,就会执行这段代码...

最近对做ios 项目遇到回调,抽空把相关资料整理下,以下是整理内容:

回调

回调就是将一段可执行的代码和一个特定的事件绑定起来。当特定的事件发生时,就会执行这段代码。
在objective-c中,有四条途径可以实现回调。

目标-动作对

在程序开始定等待前,要求“当时间发生时,向指定的对象发送某个特定的信息”。这里接收消息的对象是目标,消息的选择器是动作。

辅助对象

在程序开始等待之前,要求“当时间发生时,向遵守相应协议的辅助对象发送消息”。委托对象和数据源是常见的辅助对象。

通知

苹果公司提供了一种称为通知中心的对象。在程序开始等待前,就可以告知通知中心”某个对象正在等待某些特定的通知。当其中的某个通知出现时,向指定的对象发送特定的消息”。当事件发生时,相关的对象会向通知中心发布通知,然后再由通知中心将通知转发给正在等待通知的对象。

block对象

block是一段可执行代码。在程序开始等待前,声明一个block对象,当事件发生时,执行这段block对象。

nsrunloop

ios中有一个nsrunloop类,nsrunloop实例会持续等待着,当特定的事件发生时,就会向相应的对象发送消息。nsrunloop实例会在特定的事件发生时触发回调。

循环

实现回调之前要先创建一个循环:

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

目标-动作对

创建一个拥有nsrunloop对象和nstimer对象的应用程序。每隔两秒,nstimer对象会向其目标发送指定的动作消息,创建一个新的类,名为bnrlogger,为nstimer对象的目标。
在bnrlogger.h中声明动作方法:

#import <foundation/foundation.h>

@interface bnrlogger : nsobject<nsurlsessiondatadelegate>
@property(nonatomic) nsdate *lasttime;

-(nsstring *) lasttimestring;
-(void)updatelasttime: (nstimer *) t;

@end

在bnrlogger.m中实现方法:

#import "bnrlogger.h"

@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:self.lasttime];
}

-(void)updatelasttime:(nstimer *)t
{
  nsdate *now=[nsdate date];
  [self setlasttime:now];
  nslog(@"just set time to %@",self.lasttimestring);
}

@end

main.m中创建一个bnrlogger实例:

#import <foundation/foundation.h>
#import "bnrlogger.h"

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;
}


辅助对象

我的上一篇blog已经写过nsurlsession方法的使用,那么辅助对象回调的使用,将bnrlogger对象成为nsurlsession的委托对象,特定的事件发生时,该对象会向辅助对象发送消息。
main.m中创建一个nsurl对象以及nsurlrequest对象。然后创建一个nsurlsession对象,设置bnrlogger的实例为它的

委托对象:

#import <foundation/foundation.h>
#import "bnrlogger.h"

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

    //url是一张图片的下载链接
    nsurl *url = [nsurl urlwithstring:@"http://image.baidu.com/search/down?tn=download&ipn=dwnl&word=download&ie=utf8&fr=result&url=http%3a%2f%2fimg.xiazaizhijia.com%2fuploads%2f2016%2f0914%2f20160914112151862.jpg&thumburl=http%3a%2f%2fimg4.imgtn.bdimg.com%2fit%2fu%3d2349180720%2c2436282788%26fm%3d11%26gp%3d0.jpg"];

    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.根据会话对象创建一个task(发送请求)
    nsurlsessiondatatask *datatask = [session datataskwithrequest:request];

    //5.执行任务
    [datatask resume];

    [[nsrunloop currentrunloop]run];

  }
  return 0;
}

bnrlogger.h中,声明nsurlsessiondatadelegate协议:

#import <foundation/foundation.h>

@interface bnrlogger : nsobject<nsurlsessiondatadelegate>
@property (nonatomic, strong) nsmutabledata *responsedata;
@property(nonatomic) nsdate *lasttime;

-(nsstring *) lasttimestring;
-(void)updatelasttime: (nstimer *) t;

@end

bnrlogger.m中,有nsurlsession的代理方法,具体可以看nsurlsession:

#import "bnrlogger.h"

@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:self.lasttime];
}

-(void)updatelasttime:(nstimer *)t
{
  nsdate *now=[nsdate date];
  [self setlasttime:now];
  nslog(@"just set time to %@",self.lasttimestring);
}

//1.接收到服务器响应的时候调用该方法
-(void)urlsession:(nsurlsession *)session datatask:(nsurlsessiondatatask *)datatask didreceiveresponse:(nsurlresponse *)response completionhandler:(void (^)(nsurlsessionresponsedisposition))completionhandler
{
  //在该方法中可以得到响应头信息,即response
  nslog(@"didreceiveresponse--%@",[nsthread currentthread]);
  nslog(@"响应");
  //注意:需要使用completionhandler回调告诉系统应该如何处理服务器返回的数据
  //默认是取消的
  /*
   nsurlsessionresponsecancel = 0,    默认的处理方式,取消
   nsurlsessionresponseallow = 1,     接收服务器返回的数据
   nsurlsessionresponsebecomedownload = 2,变成一个下载请求
   nsurlsessionresponsebecomestream    变成一个流
   */

  completionhandler(nsurlsessionresponseallow);
}

//2.接收到服务器返回数据的时候会调用该方法,如果数据较大那么该方法可能会调用多次
-(void)urlsession:(nsurlsession *)session datatask:(nsurlsessiondatatask *)datatask didreceivedata:(nsdata *)data
{
  nslog(@"didreceivedata--%@",[nsthread currentthread]);
  nslog(@"返回");
  //拼接服务器返回的数据
  [self.responsedata appenddata:data];
}

//3.当请求完成(成功|失败)的时候会调用该方法,如果请求失败,则error有值
-(void)urlsession:(nsurlsession *)session task:(nsurlsessiontask *)task didcompletewitherror:(nserror *)error
{
  nslog(@"didcompletewitherror--%@",[nsthread currentthread]);
  nslog(@"完成");
  if(error == nil)
  {
    //解析数据
    nsdictionary *dict = [nsjsonserialization jsonobjectwithdata:self.responsedata options:kniloptions error:nil];
    nslog(@"%@",dict);
  }
}

@end

通知

当系统时区发生变化时,会向通知中心发布nssystemtimezonedidchangenotification通知,然后通知中心会将该通知转发给相应的观察者。

main.m中将bnrlogger实例注册为观察者,系统时区设置发生变化可以收到相应的通知:

 //在”辅助对象”方法应用程序中的main.m中加入这行代码
 [[nsnotificationcenter defaultcenter]addobserver:logger selector:@selector(zonechange:) name:nssystemtimezonedidchangenotification object:nil];

在bnrlogger.m中实现该方法:

 //在”辅助对象”方法应用程序中的bnrlogger.m中加入这行代码
 -(void)zonechange:(nsnotification *)note
{
  nslog(@"the system time zone has changed!");
}

block回调

把上面所讲的“通知”方法应用程序main.m中的:

[[nsnotificationcenter defaultcenter]addobserver:logger selector:@selector(zonechange:) name:nssystemtimezonedidchangenotification object:nil];

改为:

[[nsnotificationcenter defaultcenter]addobserverforname:nssystemtimezonedidchangenotification object:nil queue:[nsoperationqueue mainqueue] usingblock:^(nsnotification *note){
      nslog(@"the system time zone has changed!");
    }];

“通知”方法应用程序bnrlogger.m中的这个方法去掉:

-(void)zonechange:(nsnotification *)note
{
  nslog(@"the system time zone has changed!");
}

总结

  1. 对于只做一件事情的对象(例如),使用目标-动作对。
  2. 对于功能更复杂的对象(例如nsurlsession),使用辅助对象。最常见的辅助对象类型是委托对象。
  3. 对于要触发多个(其他对象中的)回调的对象(例如nstimezone),使用通知。
  4. block实现回调使代码便于阅读。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

上一篇:

下一篇: