iOS 面试题

来源:互联网 发布:潮流网络 编辑:程序博客网 时间:2024/05/17 20:31

面试题总结

1、iPhone4s iphone5 iphone5s iphone6 iphone6p 适配
答:1、通过分割屏幕 按每个模块的比例 布局
2、使用autolayout布局 建议配合使用VFL

2、缓存方式
1、afnetworking setImageWithURLRequest 以及数据类
2、讲数据模型 coding 归档到本地
3、(1)可以将数据缓存到本地磁盘。

(2)可以判断一个资源是否已经被缓存。如果已经被缓存,在请求相同的资源,先到本地磁盘搜索。

(3)可以判断文件缓存什么时候过期。这里为了简单起见这里,我们在请求url资源的时候,给每次请求的文件设定一个过期的时间。

(4)可以实现:如果文件已经被缓存,而且没有过期,这将本地的数据返回,否则重新请求url。

(5)可以实现:如果文件下载不成功或者下载没有完成,下次打开程序的时候,移除这些没有成功或者没有下载完成的文件。
4、把数据放到缓存目录 isExistsFile判断文件是否存在 如果存在 就不再去下载 如果不存在就去下载

5、图片缓存 还可以用sdwebimage SDImageCache

面试 题

1、BLOCK
如果要在block内修改block外声明的栈变量,那么一定要对该变量加__block标记
block引起了实例与block之间的循环引用(retain-cycle),并且给出解决方案:不直接使用self而先将self赋值给一个临时变量,然后再使用这个临时变量。

但是,大家注意,我们一定要为这个临时变量增加__block标记

2、线程
1.1 iOS有三种多线程编程的技术,分别是:

Cocoa operation
优点:不需要关心线程管理,数据同步的事情,可以把精力放在自己需要执行的操作上。
Cocoa operation 相关的类是 NSOperation ,NSOperationQueue。NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation 和 NSBlockOperation。创建NSOperation子类的对象,把对象添加到NSOperationQueue队列里执行。
GCD
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。在iOS4.0开始之后才能使用。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术。

1、NSThread的使用
NSThread 有两种直接创建方式:
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument
+ (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument
第一个是实例方法,第二个是类方法
[cpp] view plaincopy
1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];
2、NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(doSomething:)
object:nil];
[myThread start];
2.2参数的意义:
selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
target :selector消息发送的对象
argument:传输给target的唯一参数,也可以是nil

用NSObject的类方法 performSelectorInBackground:withObject: 创建一个线程:
[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

2.4 下载图片的例子:

-(void)downloadImage:(NSString *) url{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc]initWithData:data];
if(image == nil){

}else{    [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];}

}

-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}

  • (void)viewDidLoad
    {
    [super viewDidLoad];

// [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downloadImage:) object:kURL];
[thread start];
}

  • (void)didReceiveMemoryWarning
    {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
    }

@end
2.4.2线程间通讯
线程下载完图片后怎么通知主线程更新界面呢?
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
performSelectorOnMainThread是NSObject的方法,除了可以更新主线程的数据外,还可以更新其他线程的比如:
用:performSelector:onThread:withObject:waitUntilDone:

2、GCD

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

    dispatch_async(dispatch_get_main_queue(), ^{    });

});

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@”group1”);
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@”group2”);
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@”group3”);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@”updateUi”);
});
dispatch_release(group);

dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
[cpp] view plaincopy
dispatch_queue_t queue = dispatch_queue_create(“gcdtest.rongfzh.yc”, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@”dispatch_async1”);
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@”dispatch_async2”);
});
dispatch_barrier_async(queue, ^{
NSLog(@”dispatch_barrier_async”);
[NSThread sleepForTimeInterval:4];

});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@”dispatch_async3”);
});

执行某个代码片段N次。
dispatch_apply(N, globalQ, ^(size_t index) {

});

3、NSOperation

  • (void)viewDidLoad
    {
    [super viewDidLoad];
    NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self
    selector:@selector(downloadImage:)
    object:kURL];

    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperation:operation];
    // Do any additional setup after loading the view, typically from a nib.
    }

-(void)downloadImage:(NSString *)url{
NSLog(@”url:%@”, url);
NSURL *nsUrl = [NSURL URLWithString:url];
NSData *data = [[NSData alloc]initWithContentsOfURL:nsUrl];
UIImage * image = [[UIImage alloc]initWithData:data];
[self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
}
-(void)updateUI:(UIImage*) image{
self.imageView.image = image;
}

如何控制线程池中的线程数
队列里可以加入很多个NSOperation, 可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。
通过下面的代码设置:
[queue setMaxConcurrentOperationCount:5];
线程池中的线程数,也就是并发操作数。默认情况下是-1,-1表示没有限制,这样会同时运行队列中的全部的操作

XML解析

如何通过URL获取XML数据
xml解析使用AFXMLRequestOperation,需要实现苹果自带的NSXMLParserDelegate委托方法,XML中有一些不需要的协议格式内容,所以就不能像json那样解析,还得实现委托。我之前有想过能否所有的XML链接用一个类处理,而且跟服务端做了沟通,结果很不方便,效果不好。XML大多标签不同,格式也不固定,所以就有问题,使用json就要方便的多。
第一步;在.h文件中加入委托NSXMLParserDelegate
第二步;在.m文件方法中加入代码
NSURL *url = [NSURL URLWithString:@”http://113.106.90.22:5244/sshopinfo“];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFXMLRequestOperation *operation =
[AFXMLRequestOperation XMLParserRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, NSXMLParser *XMLParser) {
XMLParser.delegate = self;
[XMLParser setShouldProcessNamespaces:YES];
[XMLParser parse];
}failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, NSXMLParser *XMLParser) {
NSLog(@”%@”,error);
}];
[operation start];
第三步;在.m文件中实现委托方法
//在文档开始的时候触发
-(void)parserDidStartDocument:(NSXMLParser *)parser{
NSLog(@”解析开始!”);
}
//解析起始标记
- (void)parser:(NSXMLParser )parser didStartElement:(NSString )elementName namespaceURI:(NSString )namespaceURI qualifiedName:(NSString )qName attributes:(NSDictionary *)attributeDict{
NSLog(@”标记:%@”,elementName);

}
//解析文本节点
- (void)parser:(NSXMLParser )parser foundCharacters:(NSString )string{
NSLog(@”值:%@”,string);
}
//解析结束标记
- (void)parser:(NSXMLParser )parser didEndElement:(NSString )elementName namespaceURI:(NSString )namespaceURI qualifiedName:(NSString )qName{
NSLog(@”结束标记:%@”,elementName);
}
//文档结束时触发
-(void) parserDidEndDocument:(NSXMLParser *)parser{
NSLog(@”解析结束!”);
}

iOS 适配

layout

NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqualtoItem:self.view attribute:NSLayoutAttributeLeading multiplier:1.0f constant:20.f];

[self.view addConstraint:constraint];

Auto Layout用一个公式来计算界面之间的关系:

A = B * m + c

或者

viewA.attribute = viewB.attributs*multiplier + constant

在这个例子中公式如下:

firstButton.NSLayoutAttributeLeading = self.view.NSLayoutAtrributeLeading * 1.0f + 20f

按钮左边的位置等于父视图左边距减掉20.

把下面的约束添加到viewDidLoad里

constraint = [NSLayoutConstraint constraintWithItem:firstButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqualtoItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:30.f];

[self.view addConstraint:constraint];

该约束将会使按钮距离父视图上面30个点。Build and Run。这个按钮距离左边20个点,上面30个点。

地图 相关

————CLLocation
CLLocation类代表一个位置信息,其中还包括了方向和速度。比如我在长安街188号以5公里/小时的速度往西走。CLLocation具有下面的属性和方法:
@property CLLocationCoordinate2D coordinate; //以经度和纬度表示的位置信息
@property CLLocationDistance altitude; //海拔
@property CLLocationAccuracy horizontalAccuracy; //水平精度(如:精确到米)
@property CLLocationAccuracy verticalAccuracy; //垂直精度
@property CLLocationDirection course; //方向
@property CLLocationSpeed speed; //速度
-(NSDate *)timeStamp;
//两个位置之间的距离
-(CLLocationDistance)distanceFromLocation:(CLLocation *)location;

————-CLLocationManager
CLLocationManager类管理和提供位置服务。它的属性和方法有:
@property CLLocation *location; //位置
@property id delegate;
@property CLLocationDistance distanceFilter; //距离过滤,比如:500以内
@property CLlocationAccuracy verticalAccuracy; //垂直精度
-(void) startUpdatingLocation; //开始更新位置(比如:你在往某个地方走)
-(void)stopUpdatingLocation; //停止更新位置
-(void)startUpdatingHeading; //开始更新方向(比如:你改往东走)
-(void)stopUpdatingHeading; //停止更新方向
CLLocationManagerDelegate是一个委托类。你的应用程序需要使用这个委托类。当用户改变位置的时候,CLLocationManager回调的方法是:
-(void)locationManager:(CLLocationManager )manager didUpdateToLocation:(CLLocation )newLocation fromLocation:(CLLocation *)oldLocation;
当用户改变方向的时候,所调用的方法是:
-(void)locationManager:(CLLocationManager )manager didUpdateHeading:(CLLHeading )newHeading;
当iPhone无法获得当前位置的信息时,所回调的方法是:
-(void)locationManager: (CLLocationManager )manager didFailLoadWithError:(NSError )error;

=========================================================================
下面我们来看一个位置类的基本步骤:
一、启动定位服务
CLLocationManager *locManager = [[CLLocationManager alloc] init];
locManager.delegate = self;
[locManager startUpdatingLocation];
二、获得位置信息
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation )newLocation fromLocation: (CLLocation )oldLocation
{
NSTimeInterval howRecent = [newLocation.timestamp timeIntervalSinceNow];
if(howRecent < -10) return ; //离上次更新的时间少于10秒
if(newLocation.horizontalAccuracy > 100) return; //精度> 100米
//经度和纬度
double lat = newLocation.coordinate.latitude;
double lon = newLocation.coordinate.longitude;
}
三、获得方向信息(比如往南走)
-(void)locationManager:(CLLocationManager )manager didUpdateHeading:(CLHeading )newHeading
{
//获得方向
CLLocationDirection heading = newHeading .trueHeading;
}
四、停止定位
[locManager stopUpdatingLocation];
你可以设置你想要的精度和距离过滤:
locManager.desiredAccuracy = kLLocationAccuracyBest;
locManager.distanceFilter = 1000;

MapKit框架:
主要提供了四个功能:显示地图、CLLocation和地址之间的转换、支持在地图上做标记(比如标记北京天安门广场)、把一个位置解析成地址(比如我在水立方,想要知道确切的地址信息)。
MKMapView类:主要是完成下述功能:
——-显示地图,比如:显示北京市的地图;
——-提供多种显示方式,比如标准地图格式,卫星地图等;
——-支持地图的放大缩小;
——-支持在地图上做标记,比如标记天安门广场;
——-在地图上显示手机所在的当前位置。
MKMapView类的属性有:
@property MKCoordinateRegin region; //地图所显示的区域
@property CLLocationCoordinate2D centerCoordinate; //经度和纬度确定的中心位置
@property MKMapView mapType; //地图的显示类型,如:卫星地图
@property NSArray *annotations; //地图上的标记
@property MKUserLocation userLocation; //用户位置
@property id delegate; //委托类

装载地图时的回调方法有:
-(void)mapViewWillStartLocationMap:(MKMapView *) mapView; //开始装载地图
-(void)mapViewDidFinishLocationMap:(MKMapView *)mapView; //结束装载地图
-(void)mapVewDidFailLoadingMap:(MKMapView )mapView withError:(NSError )error; //装载失败

当位置发生转变时的回调方法:
-(void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated; //将要更改
-(void)mapView: (MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated; //已经更改

MKPlacemark、MKUserLocation和MKReverseGeocoder
在地图上做标记是通过MKPlacemark类来完成的。这个类使用(符合)MKAnnotation协议。MKAnnotation包含了多个属性,如:位置(经纬度,CLLocationCoordinate2D类型)、文字标记信息(NSString类型)等。
MKPlacemark保存了位置(经纬度)和地址(字典类)之间的映射。下面是它的初始化方法:
-(void)initWithCoordinate:(CLLocationCoordinate2D )coordinate addressDictionary:(NSDictionary )dictionary;
MKUserLocation就是指手机的当前位置,它是MKAnnotation的一个特别案例(因为MKAnnotation可以是地图上的任何标记,而MKUserLocation只是标记了地图上手机所在的当前位置)。这个类包含了多个属性:手机的位置(类型为CLLocation)、位置文字信息(类型为NSString)等。
MKPlacemark保存了位置(经纬度)和地址之间的映射。那么,有没有工具在这两者之间做转换呢?这就是MKRecerseGeocoder.给定一个位置信息,这个类可以返回相应的地址信息。MKReverseGeocoder的初始化方法为:
-(void)initWithCoodinate:(CLLocationCoordinate2D)coordinate;
下面是MKReverseGeocoder常用的一些属性和方法:
@property id delegate; //委托
-(void)start; //开始转换
-(void)cancel; //取消转换

回调的方法有:
-(void)reverseGeocoder:(MKReverseGeocoder ) geocoded didFindPlacemark:(MKPlacemark )placemark; //转换成功
-(void)reverseGeocoder : (MKReverseGeocoder )geocoded didFailWithError:(NSError )error; //转换失败

推送

Apple Push Notification的工作机制

自己的客户端发送消息到自己应用软件的apns,apns发送消息到你的手机。这个是根据令牌识别的。手机在发送消息到你的应用软件。

首先是应用程序注册消息推送。
IOS跟APNS Server要deviceToken。应用程序接受deviceToken。
应用程序将deviceToken发送给PUSH服务端程序(Provider)。
服务端程序向APNS服务发送消息。
APNS服务将消息发送给iPhone应用程序。

/* 注册推送通知功能, /
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound)];

  • (void)application:(UIApplication )app didRegisterForRemoteNotificationsWithDeviceToken:(NSData )deviceToken {

    NSString* token = [NSString stringWithFormat:@”%@”,deviceToken];
    NSLog(@”apns -> 生成的devToken:%@”, token);
    //把deviceToken发送到我们的推送服务器
    DeviceSender* sender = [[[DeviceSender alloc]initWithDelegate:self ]autorelease];
    [sender sendDeviceToPushServer:token ];
    }

  • (void)application:(UIApplication )app didFailToRegisterForRemoteNotificationsWithError:(NSError )err {

    NSLog(@”apns -> 注册推送功能时发生错误, 错误信息:\n %@”, err);
    }

  • (void)application:(UIApplication )application didReceiveRemoteNotification:(NSDictionary )userInfo
    {
    NSLog(@”\napns -> didReceiveRemoteNotification,Receive Data:\n%@”, userInfo);
    //把icon上的标记数字设置为0,
    application.applicationIconBadgeNumber = 0;
    if ([[userInfo objectForKey:@”aps”] objectForKey:@”alert”]!=NULL) {
    UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@”推送消息
    message:[[userInfo objectForKey:@”aps”] objectForKey:@”alert”]
    delegate:self
    cancelButtonTitle:@”关闭”
    otherButtonTitles:@”处理推送内容”,nil];
    alert.tag = alert_tag_push;
    [alert show];
    }
    }

nonatomic:非原子性访问,不加同步,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子型事务访问。
(atomic是Objc使用的一种线程保护技术,基本上来讲,是防止在写未完成的时候被另外一个线程读取,造成数据错误。而这种机制是耗费系统资源的,所 以在iPhone这种小型设备上,如果没有使用多线程间的通讯编程,那么nonatomic是一个非常好的选择。)

assign: 简单赋值,不更改索引计数
对基础数据类型 (NSInteger)和C数据类型(int, float, double, char, 等)

copy:建立一个索引计数为1的对象,然后释放旧对象
对NSString

retain:释放旧的对象,将旧对象的值赋予输入对象,再提高输入对象的索引计数为1
对其他NSObject和其子类

copy与retain的区别:
copy是创建一个新对象,retain是创建一个指针,引用对象计数加1。
eg: 一个NSString 对象,地址为0×1111 ,内容为@”STR”

Copy 到另外一个NSString 之后,地址为0×2222 ,内容相同,新的对象retain为1 ,旧有对象没有变化

retain 到另外一个NSString 之后,地址相同(建立一个指针,指针拷贝),内容当然相同,这个对象的retain值+1

也就是说,retain 是指针拷贝,copy 是内容拷贝。

写一个线程安全的单例
+ (id *)sharedManager
{
static AccountManager *sharedAccountManagerInstance = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
sharedAccountManagerInstance = [[self alloc] init];
});
return sharedAccountManagerInstance;
}

16什么时候用delegate,什么时候用Notification?答:delegate针对one-to-one关系,并且reciever可以返回值 给sender,notification 可以针对one-to-one/many/none,reciever无法返回值给sender.所以,delegate用于sender希望接受到 reciever的某个功能反馈值,notification用于通知多个object某个事件。

【NSNotification KVO的区别】
1)KVO的使用:
被观察者发出 addObserver:forKeyPath:options:context: 方法来添加观察者。
然后只要被观察者的keyPath值变化(注意:单纯改变其值不会调用此方法,只有通过getters和setters来改变值才会触发KVO),就会在观察者里调用方法observeValueForKeyPath:ofObject:change:context:
因此观察者需要实现方法 observeValueForKeyPath:ofObject:change:context: 来对KVO发出的通知做出响应。
这 些代码都只需在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,使得观察者与被观察者完全解耦,运用很灵活很 简便;但是KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错。

2)NSNotification的使用
这里的通知不是由被观察者发出,而是由NSNotificationCenter来统一发出,而不同通知通过唯一的通知标识名notificationName来区分,标识名由发送通知的类来起。
首先被观察者自己在必要的方法A里,通过方法postNotificationName:object:来发出通知notificationName这样发送通知者这边的工作就完成了,每次A被调用,就会发送一次通知notificationName。
然后谁要监听A的变化,就通过[NSNotificationCenter defaultCenter]的方法addObserver:selector:name:object:为观察者注册监听name为notificationName的通知然后每次发出name为notificationName的通知时,注册监听后的观察者就会调用其自己定义的方法notificationSelector来进行响应。
NSNotification的特点呢,就是需要被观察者先主动发出通知,然后观察者注册监听后再来进行响应,比KVO多了发送通知的一步,但是其优点是监听不局限于属性的变化,还可以对多种多样的状态变化进行监听,监听范围广,使用也更灵活。

iOS有三种多线程编程的技术,分别是:
1.、NSThread
2、Cocoa NSOperation
3、GCD 全称:Grand Central Dispatch
这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,也是Apple最推荐使用的。
主线程和子线程的主要区别是:主线程处理和UI相关的操作 子线程通过[obj performSelectorOnMainThread]回到主线程

NSOperation和GCD两者直接有什么区别呢?
GCD是底层的C语言构成的API,而NSOperationQueue及相关对象是Objc的对象。在GCD中,在队列中执行的是由block构成的任务,这是一个轻量级的数据结构;而Operation作为一个对象,为我们提供了更多的选择;
在NSOperationQueue中,我们可以随时取消已经设定要准备执行的任务(当然,已经开始的任务就无法阻止了),而GCD没法停止已经加入queue的block(其实是有的,但需要许多复杂的代码);
NSOperation能够方便地设置依赖关系,我们可以让一个Operation依赖于另一个Operation,这样的话尽管两个Operation处于同一个并行队列中,但前者会直到后者执行完毕后再执行;
我们能将KVO应用在NSOperation中,可以监听一个Operation是否完成或取消,这样子能比GCD更加有效地掌控我们执行的后台任务;
在NSOperation中,我们能够设置NSOperation的priority优先级,能够使同一个并行队列中的任务区分先后地执行,而在GCD中,我们只能区分不同任务队列的优先级,如果要区分block任务的优先级,也需要大量的复杂代码;
我们能够对NSOperation进行继承,在这之上添加成员变量与成员方法,提高整个代码的复用度,这比简单地将block任务排入执行队列更有自由度,能够在其之上添加更多自定制的功能。

dispatch queue分为下面三种:
Serial(连续的 系列的)
又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
Concurrent (同时发生的)
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
Main dispatch queue
它是全局可用的 在应用程序主线程上执行任务的。

1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下:
2、dispatch_group_async的使用
dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。下面是一段例子代码:
3、dispatch_barrier_async的使用
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下:
4、dispatch_apply
执行某个代码片段N次。

loadView、viewDidLoad及viewDidUnload的关系

loadView
1.什么时候被调用?
每次访问UIViewController的view(比如controller.view, self.view)而且view为nil loadView方法就会被调用
2.有什么作用?
loadView方法是用来负责创建UIViewController的view
3.默认实现是怎样的?
(1)它会先去查找与UIViewController相关联的xib文件 通过加载xib文件来创建UIViewController的view
如果在初始化UIViewController指定了xib文件名 就会根据传入的xib文件名加载对应的xib文件
如果没有指定传入xib文件名 就会加载跟UIViewController同名的xib文件
(2)如果没有找到相关联的xib文件 就会创建一个空白的UIView 然后赋值给UIViewController的view属性
4.怎样正确使用这个方法
重写loadView方法 并且不需要调用[super loadView] 因为 [super loadview]负责创建一个空白的UIView 我们既然要通过代码自定义UIView 那么就没必要事先创建一个空白的UIView

viewDidLoad
1.什么时候被调用?
不管你是通过xib文件还是重写loadView创建UIViewController的view 在view创建完毕后 最终都会调用viewDidLoad方法
2.有什么作用?
一般我们会在这里做界面上的初始化操作,比如往view中添加一些子试图 从数据库或者网络加载模型数据装配到子视图中

viewDidUnload
1.什么时候被调用
IOS设备的内存是极其有限的 如果应用程序占用的内存过多的话 系统就会对应用程序发出内存警告 UIViewController就会收到didReceiveMemoryWarning消息 didReceiveMemoryWarning方法的默认实现是 如果当前UIViewController的view不在应用程序的视图层次结构中,即view的superview为nil的时候 就会将view释放 并且调用viewDidUnload方法
2.有什么作用?
发出内存警告且view被释放的时候就会调用viewDidUnload方法 所以一般在释放资源 主要是释放界面元素相关的资源 将相关的事例都赋值为nil

3.dealloc也是用来释放资源的,那跟viewDidUnload有什么关系?
当发出内存警告调用viewDidUnload方法时 只是释放了view 并没有释放UIViewController 所以并不会调用dealloc方法 dealloc方法只会在UIViewController被释放的时候调用

三个方法的关系
1.第一次访问UIViewController的view时,view为nil,然后就会调用loadView方法创建view
2.view创建完毕后会调用viewDidLoad方法进行界面元素的初始化
3.当内存警告时,系统可能会释放UIViewController的view,将view赋值为nil,并且调用viewDidUnload方法
4.当再次访问UIViewController的view时,view已经在3中被赋值为nil,所以又会调用loadView方法重新创建view
5.view被重新创建完毕后,还是会调用viewDidLoad方法进行界面元素的初始化

Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的Autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用Release。

  • (id)sharedInstance
    {
    static id sharedInstance;
    static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
sharedInstance = [[NSObject alloc] init];
});

return sharedInstance;

}

当一个视图控制器被创建,并在屏幕上现实的时候。代码的执行顺序
1、 alloc 创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear 视图已在屏幕上渲染完成

当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear 视图将被从屏幕上移除之前执行
2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
3、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放

关于viewDidUnload :在发生内存警告的时候如果本视图不是当前屏幕上正在显示的视图的话, viewDidUnload将会被执行,本视图的所有子视图将被销毁,以释放内存,此时开发者需要手动对viewLoad、viewDidLoad中创建的对象释放内存。 因为当这个视图再次显示在屏幕上的时候,viewLoad、viewDidLoad 再次被调用,以便再次构造视图。

当把语义特性声明为retain时,setter和getter方法内部实现
- (void)setName:(NSString *)name{
if (_name != name) {
[ _name release];
_name = [name retain];
}
}
- (NSString *)name{
return [[ _name retain] autorelease];
}

循环引用的问题这样理解:

比如在main函数中创建了两个类的对象A和B,现在引用计数都是1。现在让A和B互相引用(A有一个属性是B对象,属性说明是retain;B有一个属性是A对象,属性说明是retain),现在两个对象的引用计数都增加了1,都变成了2。

现在执行[A release]; [B release]; 此时创建对象的main函数已经释放了自己对对象的所有权,但是此时A和B的引用计数都还是1,因为他们互相引用了。

这时你发现A和B将无法释放,因为要想释放A必须先释放B,在B的dealloc方法中再释放A。同理,要想释放B必须先释放A,在A的dealloc方法中再释放B。所以这两个对象将一直存在在内存中而不释放。这就是所谓的循环引用的问题。要想解决这个问题,一般的方法可以将引用的属性设置为assign,而不是retain来处理。

自动释放池是什么,如何工作?
当您向一个对象发送一个autorelease消息时,Cocoa就会将该对象的一个引用放入到最新的自动释放池。它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,自动释放池就会被释放,池中的所有对象也就被释放。

“”表示从当前项目路径开始寻找文件,如果找不到,则到系统(项目)中配置的头文件路径去找;
<>表示直接到系统(项目)中配置的头文件路径去找。
“”常用于引用类
<>常引用框架

一种是通过#import方式引入;另一种是通过@class引入;

#import 全部引用 引用类的所有信息,包括被引用类的变量和方法 @class只是告诉编译器 只是类的声明具体这个类里有什么信息,不知道(解决循环导入)

IOS学习笔记48–一些常见的IOS知识点+面试题
分类: IOS技术开发 2013-08-15 17:17 2543人阅读 评论(0) 收藏 举报
IOS知识点
1、堆和栈什么区别?
答:管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。

2、数组和链表什么区别?

答:数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。

   链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。

3、delegate和notification什么区别,什么情况使用?

答:Delegate:
消息的发送者(sender)告知接收者(receiver)某个事件将要发生,delegate同意然然后发送者响应事件,

    delegate机制使得接收者可以改变发送者的行为。    通常发送者和接收者的关系是直接的一对多的关系。  Notification:  消息的发送者告知接收者事件已经发生或者将要发送,仅此而已,接收者并不能反过来影响发送者的行为。  通常发送者和接收者的关系是间接的多对多关系。

4、什么是MVC,为什么使用MVC,有什么好处?

答: 分别为: 模型(Model),视图(View)和控制Controller)。
模型(Model) “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。

                            “模型”有对数据直接访问的权力,例如对数据库的访问。      视图(View) 视图层能够实现数据有目的显示。      控制器(Controller) 控制器起到不同层面间的组织作用,用于控制应用程序的流程。

5、从一个数组中找出重复的元素打印出来

NSArray *arr = [NSArrayarrayWithObjects:@”1”,@”2”,@”1”,@”7”,@”4”,@”5”,@”2”,@”6”,@”5”,nil];
NSMutableArray *arrmu = [[NSMutableArrayalloc]init];//过滤
NSMutableArray *sameArray = [[NSMutableArrayalloc]init];//找出相同的
for (int i = 0 ; i < [arrcount]; i++) {

  id str = [arr objectAtIndex:i];   if ([arrmu count] == 0)    {        [arrmuaddObject:str];    }   else{       BOOL flag = NO;       for (int j = 0; j < [arrmucount]; j++ ) {           if ([strisEqual:[arrmu objectAtIndex:j]])            {                [sameArrayaddObject:str];                flag =YES;               break;            }           else{                flag =NO;            }        }       if (flag == NO) {            [ arrmuaddObject:str];        }    }}

NSLog(@”sameArray : %@”,sameArray);
还有两种直接找出的方法,上代码:
一:
NSArray *arr = [NSArrayarrayWithObjects:@”1”,@”2”,@”1”,nil];
NSSet *set = [NSSetsetWithArray:arr];
NSLog(@”%@”,[setallObjects]);
二:
NSArray *arr =@[@1,@2,@1];
NSMutableDictionary *dict = [NSMutableDictionarydictionary];
for (NSNumber *numberin arr) {
[dictsetObject:numberforKey:number];
}
NSLog(@”%@”,[dictallValues]);

6、UITableView能否绑定多个数据源?
答:不能

7、一个UIViewController能否管理多个UITableView ?

答:可以

8、ios4、5、6相对于之前的版本添加了哪些新特性?
这个就比较多了,比如:抛弃谷歌地图 新推Maps应用 ,大幅加强中国本地化支持,Siri开口讲普通话,通过iCloud体验分享乐趣,Passbook电子票券管理,随时随地的FaceTime,电话功能增强,Safari支持全屏浏览,Mail应用新增VIP,万能辅助:更强大等等了

9、同步请求和异步请求什么区别?
答:发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作,

  异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然可以对UI进行操作,程序可以继续运行。

10、iOS中的多线程操作、多线程方式

答:iOS提供了方便的多线程调用机制:NSOperation和NSOperationQueue。它的使用方法也很简单,

一般都是将NSOperation对象加入到NSOperationQueue队列中,加入后队列就开始处理,知道任务操作完成。

11、UIViewController的生命周期

答:当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
// 视图显示在屏幕上的顺序

 1、 alloc                    创建对象,分配空间。2、init (initWithNibName)    初始化对象,初始化数据。3、loadView                   从nib载入视图, 这一步不需要去干涉。除非没有使用xib文件创建视图。4、viewDidLoad                加载完毕,可以进行自定义数据以及动态创建其他控件。5、viewWillAppear             视图将出现在屏幕之前,马上这个视图即将显示在屏幕上。6、viewDidAppear              视图已在屏幕上渲染完成。// 视图将被从屏幕上移除的顺序1、viewWillDisappear          视图将被从屏幕上移除之前执行。2、viewDidDisappear           视图已经被从屏幕上移除。3、dealloc                    视图被销毁,此时需要在init和viewDidLoad中创建的对象进行释放。4、viewDidUnload              出现内存警告在内存不足时执行,并对所有非当前显示的controller执行。 本视图的所有子视图将被销毁,以释放内存,此时开发者需要手动对viewLoad、viewDidLoad中创建的对象释放内存。 因为当这个视图再次显示在屏幕上的时候,viewLoad、viewDidLoad 再次被调用,以便再次构造视图。

12、Autorerelease对象什么时候释放?

答:autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的Autorelease pool中,当该pool被释放时,该pool中的所有Object会被调用Release。

13、iOS数据持久化方式

答:四种:属性列表、对象归档、SQLite3和Core Data

14、Object-c的类可以多重继承么?可以实现多个接口么?Category是什么?重写一个类的方式用继承好还是分类好?为什么?

答:Object-c的类不可以多重继承;可以实现多个接口,通过实现多个接口可以完成C++的多重继承;Category是类别,一般情况用分类好,用Category去重写类的方法,仅对本Category有效,不会影响到其他类与原有类的关系。

  1. import 跟#include 又什么区别,@class呢, #import<> 跟 #import””又什么区别?

    答:#import是Objective-C导入头文件的关键字,#include是C/C++导入头文件的关键字,使 用#import头文件会自动只导入一次,不会重复导入,相当于#include和#pragma once;@class告诉编译器某个类的声明,当执行时,才去查看类的实现文件,可以解决头文件的相互包含;#import<>用来包含系 统的头文件,#import””用来包含用户头文件。

16.属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种情况下用?

答:readwrite 是可读可写特性;需要生成getter方法和setter方法时

readonly 是只读特性 只会生成getter方法 不会生成setter方法 ;不希望属性在类外改变

assign 是赋值特性,setter方法将传入参数赋值给实例变量;仅设置变量时;

retain 表示持有特性,setter方法将传入参数先保留,再赋值,传入参数的retaincount会+1;

copy 表示赋值特性,setter方法将传入对象复制一份;需要完全一份新的变量时。

nonatomic 非原子操作,决定编译器生成的setter getter是否是原子操作,atomic表示多线程安全,一般使用nonatomic

17.常见的object-c的数据类型有那些, 和C的基本数据类型有什么区别?如:NSInteger和int

答:object-c的数据类型有 NSString,NSNumber,NSArray,NSMutableArray,NSData等等,这些都是class,创建后便是对象,而C语言的基本数据类型int,只是一定字节的内存空间,用于存放数值;而object-c的NSNumber包含有父类NSObject的方法和 NSNumber自己的方法,可以完成复杂的操作。

18.Objective-C如何对内存管理的,说说你的看法和解决方法?
答:Objective-C的内存管理主要有三种方式ARC(自动内存计数)、手动内存计数、内存池。
解决方法的话: 谁持有,谁释放。

19.如何对iOS设备进行性能测试?
答:Profile-> Instruments ->Time Profiler

20.Object C中创建线程的方法是什么?如果在主线程中执行代码,方法是什么?如果想延时执行代码、方法又是什么?
答:线程创建有三种方法:使用NSThread创建、使用 GCD的dispatch、使用子类化的NSOperation,然后将其加入NSOperationQueue;在主线程执行代码,方法是 performSelectorOnMainThread,如果想延时执行代码可以用performSelector:onThread:withObject:waitUntilDone:

21.描述一下iOS SDK中如何实现MVC的开发模式
答:MVC是:模型–视图–控制 开发模式,对于iOS SDK,所有的View都是视图层的,它应该独立于模型层,由视图控制层来控制。所有的用户数据都是模型层,它应该独立于视图。所有的ViewController都是控制层,由它负责控制视图,访问模型数据。

22.定义属性时,什么情况使用copy、assign、retain?
答:assign用于简单数据类型,如NSInteger,double,bool, 其实还有后面的block等;
retain和copy用于对象,copy用于当a指向一个对象,b也想指向同样的对象的时候,如果用assign,a如果释放,再调用b会crash,如果用copy 的方式,a和b各自有自己的内存, 就可以解决这个问题。
retain 会使计数器加一,也可以解决assign的问题。
另外:atomic和nonatomic用来决定编译器生成的getter和setter是否为原子操作。在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。
加了atomic,setter函数会变成下面这样:
if (property != newValue) {
[property release];
property = [newValue retain];
}

  1. Object-C有私有方法吗?私有变量呢?

    答:objective-c – 类里面的方法只有两种, 静态方法和实例方法,所有实例变量默认都是私有的,所有实例方法默认都是公有的。

24.浅拷贝和深拷贝区别是什么

答:浅拷贝:只复制指向对象的指针,而不复制引用对象本身。

深拷贝:复制引用对象本身。

25.自动释放池是什么,如何工作
答: 当您向一个对象发送一个autorelease消息时,Cocoa就会将该对 象的一个引用放入到最新的自动释放池。

    它仍然是个正当的对象,因此自动释放池定义的作用域内的其它对象可以向它发送消息。当程序执行到作用域结束的位置时,    自动释放池就会被释放,池中的所有对象也就被释放。

26.单件实例是什么

答: Foundation 和 Application Kit 框架中的一些类只允许创建单件对象,即这些类在当前进程中的唯一实例。

   举例:NSFileManager 和NSWorkspace类在使用时都是基于进程进行单件对象的实例化。   当向这些类请求实例的时候,它们会向您传递单一实例的一个引用,如果该实例还不存在,则首先进行实例的分配 和初始化。

27.类别的作用?继承和类别在实现中有何区别?
答:category 可以在不获悉,不改变原来代码的情况下往里面添加新的方法,只能添加,不能删除修改。

  并且如果类别和原来类中的方法产生名称冲突,则类别将覆盖原来的方法,因为类别具有更高的优先级。

类别主要有3个作用:

(1)将类的实现分散到多个不同文件或多个不同框架中。

  (2)创建对私有方法的前向引用。

(3)向对象添加非正式协议。

  继承可以增加,修改或者删除方法,并且可以增加属性。

28.类别和类扩展的区别。
答:category和extensions的不同在于 后者可以添加属性。另外后者添加的方法是必须要实现的。
extensions可以认为是一个私有的Category。

29.KVO and KVC?

答:kvc:键 - 值编码是一种间接访问对象的属性,使用字符串来标识属性,而不是通过调用存取方法,直接或通过实例变量访问的机制。
很多情况下可以简化程序代码。apple文档其实给了一个很好的例子。
kvo:键值观察机制,他提供了观察某一属性变化的方法,极大的简化了代码。
具体用看到用到过的一个地方是对于按钮点击变化状态的的监控。
比如我自定义的一个button
[cpp]

[self addObserver:self forKeyPath:@”highlighted” options:0 context:nil];

pragma mark KVO

  • (void)observeValueForKeyPath:(NSString )keyPath ofObject:(id)object change:(NSDictionary )change context:(void *)context
    {

    if ([keyPath isEqualToString:@”highlighted”] ) {

      [self setNeedsDisplay];

    }
    }
    对于系统是根据keypath去取的到相应的值发生改变,理论上来说是和kvc机制的道理是一样的。
    对于kvc机制如何通过key寻找到value:
    “当通过KVC调用对象时,比如:[self valueForKey:@”someKey”]时,程序会自动试图通过几种不同的方式解析这个调用。首先查找对象是否带有 someKey 这个方法,如果没找到,会继续查找对象是否带有someKey这个实例变量(iVar),如果还没有找到,程序会继续试图调用
    -(id) valueForUndefinedKey:这个方法。如果这个方法还是没有被实现的话,程序会抛出一个NSUndefinedKeyException异常错误。

(cocoachina.com注:Key-Value Coding查找方法的时候,不仅仅会查找someKey这个方法,还会查找getsomeKey这个方法,前面加一个get,或者_someKey以及_getsomeKey这几种形式。同时,查找实例变量的时候也会不仅仅查找someKey这个变量,也会查找_someKey这个变量是否存在。)

设计valueForUndefinedKey:方法的主要目的是当你使用-(id)valueForKey方法从对象中请求值时,对象能够在错误发生前,有最后的机会响应这个请求。这样做有很多好处,下面的两个例子说明了这样做的好处。“
来至cocoa,这个说法应该挺有道理。

因为我们知道button却是存在一个highlighted实例变量.因此为何上面我们只是add一个相关的keypath就行了,

可以按照kvc查找的逻辑理解,就说的过去了。

30.代理的作用?
答:代理的目的是改变或传递控制链。允许一个类在某些特定时刻通知到其他类,而不需要获取到那些类的指针。可以减少框架复杂度。
另外一点,代理可以理解为java中的回调监听机制的一种类似。

31.说说响应链

答: 事件响应链。包括点击事件,画面刷新事件等。在视图栈内从上至下,或者从下之上传播。

32.frame和bounds有什么不同?

答:frame指的是:该view在父view坐标系统中的位置和大小。(参照点是父亲的坐标系统)
bounds指的是:该view在本身坐标系统中 的位置和大小。(参照点是本身坐标系统)

33.方法和选择器有何不同?

答:selector是一个方法的名字,method是一个组合体。

34.Object-c的类可以多重继承么?可以实现多个接口么?重写一个类的方式用继承好还是分类好?为什么?
答:Objective-c只支持单继承,如果要实现多继承的话,可以通过类别和协议的方式来实现,cocoa 中所有的类都是NSObject 的子类,多继承在这里是用protocol 委托代理 来实现的。

35.ARC自动引用技术
答:1.ARC是编译特性,不是运行时特性,只是在编译的时候,编译器会自动加上释放代码
2.不能调用release、retain、autorelease、retainCount
3.dealloc注意
1> 不能在dealloc中调用[super dealloc]
2> 不能在dealloc中释放资源
4.@property参数说明
1> retain 改为 strong
2> 基本数据类型(int\float)还是用assign
3> copy 还是 copy
4> 如果2个对象循环引用,一端用strong,一端用weak
5> weak是用在对象上,weak其实作用跟assign相当
5.ARC中只允许使用通过@autoreleasepool {}创建自动释放池

36 GCD技术
答:Grand Central Dispatch简称GCD 解决多核并行运算的一种方案
看代码就行:
// Grand Central Dispatch简称GCD技术

// Do any additional setup after loading the view.

// dispatch_queue_t newDispath = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async(newDispath, ^{
// [self downloadImage];
// });

// #defineDISPATCH_QUEUE_PRIORITY_HIGH 2
// #defineDISPATCH_QUEUE_PRIORITY_DEFAULT 0
// #defineDISPATCH_QUEUE_PRIORITY_LOW (-2)
// #defineDISPATCH_QUEUE_PRIORITY_BACKGROUNDINT16_MIN

/*dispatch queue分为下面三种:
* Serial:又称为private dispatch queues,同时只执行一个任务。Serial queue通常用于同步访问特定的资源或数据。当你创建多 个 Serial queue时,虽然它们各自是同步执行的,但Serial queue与Serial queue之间是并发执行的。
* Concurrent: 又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
* Main dispatch queue它是全局可用的serial queue,它是在应用程序主线程上执行任务的
*/

// 一般GCD 可以如下操作

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
// 耗时的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});

[selfexampleDispatch];/* *系统给每一个应用程序提供了三个concurrent dispatch queues。 *这三个并发调度队列是全局的,它们只有优先级的不同。 *因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列 */

dispatch_queue_t globalQ =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

NSLog(@"global:%p",globalQ);dispatch_queue_t mainQ =dispatch_get_main_queue(); NSLog(@"mainQ:%p",mainQ);/* *虽然dispatch queue是引用计数的对象,但是以上两个都是全局的队列,不用retain或release。 *//* *dispatch_group_async可以实现监听一组任务是否完成,完成后得到通知执行其他的操作。 *这个方法很有用,比如你执行三个下载任务,当三个任务都下载完成后你才通知界面说完成的了。 */timeInt = 0;[NSTimerscheduledTimerWithTimeInterval:1                                target:self                              selector:@selector(checkingTime)                              userInfo:nil                               repeats:YES];[selfexampleDispath_group];

/*dispatch_barrier_async的使用
*dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
*/

[selfexampleDispatch_barrier];

/*dispatch_apply
*执行某个代码片段N次。
*/
dispatch_apply(5, globalQ, ^(size_t index) {
// 执行5次
});

0 0
原创粉丝点击