多线程的注意点
1.不要同时开太多的线程(1~3条线程即可,不要超过5条)
2.线程概念
1> 主线程 : UI线程,显示、刷新UI界面,处理UI控件的事件
2> 子线程 : 后台线程,异步线程
3.不要把耗时的操作放在主线程,要放在子线程中执行
一、NSThread
1.创建和启动线程的3种方式
1> 先创建,后启动
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];
// 启动
[thread start];
2> 创建完自动启动
[NSThread detachNewThreadSelector:@selector(download:) toTarget:self withObject:nil];
3> 隐式创建(自动启动)
[self performSelectorInBackground:@selector(download:) withObject:nil];
2.常见方法
1> 获得当前线程
+ (NSThread *)currentThread;
2> 获得主线程
+ (NSThread *)mainThread;
3> 睡眠(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
4> 设置线程的名字
- (void)setName:(NSString *)n;
- (NSString *)name;
二、线程同步(掌握)
1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题
2.实现:给代码加一个互斥锁(同步锁)
@synchronized(self) {
// 被锁住的代码
}
三、GCD
1.队列和任务
1> 任务 :需要执行什么操作
* 用block来封装任务
2> 队列 :存放任务
* 全局的并发队列 : 可以让任务并发执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
* 自己创建的串行队列 : 让任务一个接着一个执行
dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
* 主队列 : 让任务在主线程执行
dispatch_queue_t queue = dispatch_get_main_queue();
2.执行任务的函数
1> 同步执行 : 不具备开启新线程的能力
dispatch_sync...
2> 异步执行 : 具备开启新线程的能力
dispatch_async...
3.常见的组合(掌握)
1> dispatch_async + 全局并发队列
2> dispatch_async + 自己创建的串行队列
4.线程间的通信(掌握)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库
* 主头文件 : #import <dispatch/dispatch.h>
6.延迟执行(掌握)
1> perform....
// 3秒后自动回到当前线程调用self的download:方法,并且传递参数:@"http://555.jpg"
[self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
2> dispatch_after...
// 任务放到哪个队列中执行
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
double delay = 3; // 延迟多少秒
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
// 3秒后需要执行的任务
});
7.一次性代码(掌握)
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 这里面的代码,在程序运行过程中,永远只会执行1次
});
四、NSOperation和NSOperationQueue
1.队列的类型
1> 主队列
* [NSOperationQueue mainQueue]
* 添加到"主队列"中的操作,都会放到主线程中执行
2> 非主队列
* [[NSOperationQueue alloc] init]
* 添加到"非主队列"中的操作,都会放到子线程中执行
2.队列添加任务
* - (void)addOperation:(NSOperation *)op;
* - (void)addOperationWithBlock:(void (^)(void))block;
3.常见用法
1> 设置最大并发数
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
2> 队列的其他操作
* 取消所有的操作
- (void)cancelAllOperations;
* 暂停所有的操作
[queue setSuspended:YES];
* 恢复所有的操作
[queue setSuspended:NO];
4.操作之间的依赖(面试题)
* NSOperation之间可以设置依赖来保证执行顺序
* [operationB addDependency:operationA];
// 操作B依赖于操作A,等操作A执行完毕后,才会执行操作B
* 注意:不能相互依赖,比如A依赖B,B依赖A
* 可以在不同queue的NSOperation之间创建依赖关系
5.线程之间的通信
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
// 1.执行一些比较耗时的操作
// 2.回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
}];
五、从其他线程回到主线程的方式
1.perform...
[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
2.GCD
dispatch_async(dispatch_get_main_queue(), ^{
});
3.NSOperationQueue
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
六、第三方框架的使用建议
1.用第三方框架的目的
1> 开发效率:快速开发,人家封装好的一行代码顶自己写的N行
2> 为了使用这个功能最牛逼的实现
2.第三方框架过多,很多坏处(忽略不计)
1> 管理、升级、更新
2> 第三方框架有BUG,等待作者解决
3> 第三方框架的作者不幸去世、停止更新(潜在的BUG无人解决)
4> 感觉:自己好水
3.比如
流媒体:播放在线视频、音频(边下载边播放)
非常了解音频、视频文件的格式
每一种视频都有自己的解码方式(C\C++)
4.总结
1> 站在巨人的肩膀上编程
2> 没有关系,使劲用那么比较稳定的第三方框架
七、SDWebImage的图片下载
1.面试题
1> 如何防止一个url对应的图片重复下载
* “cell下载图片思路 – 有沙盒缓存”
2> SDWebImage的默认缓存时长是多少?
* 1个星期
3> SDWebImage底层是怎么实现的?
* 上课PPT的“cell下载图片思路 – 有沙盒缓存”
2.SDWebImage
1> 常用方法
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock;
- (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock;
2> SDWebImageOptions
* SDWebImageRetryFailed : 下载失败后,会自动重新下载
* SDWebImageLowPriority : 当正在进行UI交互时,自动暂停内部的一些下载操作
* SDWebImageRetryFailed | SDWebImageLowPriority : 拥有上面2个功能
sudo chmod u+x 文件名
sudo chmod 700 文件名
sudo chmod 777 文件名
地图定位
CoreLocation
CLLocation *bjLoc Latitude 39.54 longitude:116.28
CLLocation *bjLoc Latitude 23.05 longitude:113.15
1、CoreLocation
*CLLocationManager局部变量不能定位
*模拟器不支持定位,要手动
代理
startUpdatingLocation
stopUpdatingLocation
locationManager:didUpdateLocations
a> *CLLocation
b> *经纬度
CLLocationCoordinate2D
c> *海拔
d> location.altitude
e> *速度
location.speed
f> self.locManager.distanceFilter = 1000;
//精确到1米 越精确精耗电
g> self.locManager.desiredAccuracy = 1;
*距离计算
CLLocation distanceFromLocation
广州 CLLocation *bjLoc Latitude 39.54 longitude:116.28
北京 CLLocation *bjLoc Latitude 23.05 longitude:113.15
*plist文件添加隐私描述
Privacy - Location Usage Description
计算两个经纬度间的直线距离
2、地理编码
CLGeocoder
>地理编码
*把地点名称解析成详细地理信息
self.geoCoder geocodeAddressString
placemarks放CLPlacemark(位置标记)
CLPlacemark里的属性成员
CLLocation *location = placeMark.location;
CLLocationCoordinate2D coordinate = location.coordinate;
注:longitude与latitude不要写错
>把地理位置解析成详细地理信息(116.35 40.16)
反地理编码
reverseGeocodeLocation
补充.
1.CLPlacemark的addressDictionary属性 遍历字典数据
addressDictionary enumerateKeysAndObjectsUsingBlock
2.block是在主线程调用,所以可以直接在block刷新UI
name : 地名
thoroughfare : 街道
ubThoroughfare : 街道相关信息,例如门牌等
locality : 城市
subLocality : 城市相关信息,例如标志性建筑
administrativeArea : 直辖市
subAdministrativeArea : 其他行政区域信息
postalCode : 邮编
ISOcountryCode : 国家编码
country; : 国家
inlandWater : 水源、湖泊
ocean; : 海洋
areasOfInterest : 关联的或利益相关的地标
MapKit
1.MapKit使用的基本使用
*创建项目
添加框架
导入MapKit
运行项目
*设置mapType地理显示类型
*设置跟踪模式userTrackingMode
*设置代理
didUpdateUserLocation方法
大头针userLocation.title = @"北京";
位置信息userLocation.coordinate
显示居中mapView setCenterCoordinate
显示区域 mapView setRegion
regionDidChangeAnimated方法
*返回原点
2.大头针(随机添加)
*添加tap手势
*获取点位置转成mapView的地理位置
mapview的点转成经纬度
[self.mapView convertPoint:tapPoint toCoordinateFromView:tap.view]
*添加CZAnnotation实现MKAnnotation代理
*随机添加20个头针
在触摸点的位置随机添加20个位置arc4random_uniform(100)/ 1000.0
3.自定义大头针
传智地址 经度:116.3544839331055纬度:40.06214218062825
>
*自定义一个Tuangou大头针模型,先不要加图片属性
*touch的时候添加大头针
引出下面两个代理方法
mapView:viewForAnnotation(大头针模型)
返回nil时,系统会自己添加大头针
mapView:didAddAnnotationViews(大头什视图)
MKModernUserLocationView(用户无法用,苹果私有api)
MKPinAnnotationView
返回大头针
从缓存池里取(与tableView一样取法)
自己实现MKPinAnnotationView,要想显示标题与子标题,得设置pinView的canShowCallout canShowOffset
属性为YES
*实现从天而降效果animatesDrop
*pinColor别针颜色(枚举)
注:要写return pinView;
>直接让购View返回的是MKAnnotationView
然后在团购模型中添加图片
设置canShowCallout为YES
设置annoView.image改变大头针图片
设置calloutoffset = CGPointMake(0,-10)
*添加右边rightCalloutAccessoryView
*添加左边leftCalloutAccessoryView
4.自定义大头针描述
150 x 80
选添加团购大头针
再添加团购描述大头针
5.画线路
跟大头针一样
//方向对象
addOverlay
MKPolyline
MKPolylineRenderer
//计算路线
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
//设置起点
MKPlacemark *fromPm = [[MKPlacemark alloc] initWithPlacemark:from];
request.source = [[MKMapItem alloc] initWithPlacemark:fromPm];
//设置终点
MKPlacemark *toPm = [[MKPlacemark alloc] initWithPlacemark:to];
request.destination = [[MKMapItem alloc] initWithPlacemark:toPm];
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
//计算路线
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
NSLog(@"共有几条路线 %d",response.routes.count);
for (MKRoute *route in response.routes) {
[self.mapView addOverlay:route.polyline];
}
}];
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{
MKPolylineRenderer *render = [[MKPolylineRenderer alloc] initWithOverlay:overlay];
render.strokeColor = [UIColor blueColor];
render.lineWidth = 5
return render;
}
6.使用系统的地图导航
[self.geocoder geocodeAddressString:@"广州" completionHandler:^(NSArray *placemarks, NSError *error) {
MKMapItem *currentItem = [MKMapItem mapItemForCurrentLocation];
CLPlacemark *gzCLPM = [placemarks lastObject];
MKPlacemark *gzMKPM = [[MKPlacemark alloc] initWithPlacemark:gzCLPM];
MKMapItem *destItem = [[MKMapItem alloc] initWithPlacemark:gzMKPM];
NSMutableDictionary *options = [NSMutableDictionary dictionary];
options[MKLaunchOptionsDirectionsModeKey] = MKLaunchOptionsDirectionsModeDriving;//行车路线
options[MKLaunchOptionsShowsTrafficKey] = @YES;
options[MKLaunchOptionsMapTypeKey] = [NSNumber numberWithInt:MKMapTypeSatellite];
[MKMapItem openMapsWithItems:@[currentItem,destItem] launchOptions:options];
}];
转载于:https://my.oschina.net/CeeYang/blog/602593