2017-11-17 14:54:04 u011374880 阅读数 2496
LIVE拍摄的原图发送无法显示解决办法

iOS 11中,如果你是iPhone 7及以上设备,系统用了新的格式来存储视频和图片,


如果你的App支持上传图片原文件,那么很可能会有图片无法显示的问题。

读取图片原文件的代码一般是下面这样的,传到后台之后得到一个url,webview和UIImage是无法显示的。

[[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
    if (imageData) {
        
    }
}];
当我们讲适配的时候,往往比较多地关注UI的适配,容易忽略一些看不见的东西。
识别HEIF
识别HEIF文件的方法和识别GIF一样,对比文件UTI(uniformTypeIdentifier)
__block BOOL isHEIF = NO;
if (iOSVersionGreaterThanOrEqualTo(@"9.0")) {
    NSArray *resourceList = [PHAssetResource assetResourcesForAsset:phAsset];
    [resourceList enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        PHAssetResource *resource = obj;
        NSString *UTI = resource.uniformTypeIdentifier;
        if ([UTI isEqualToString:@"public.heif"] || [UTI isEqualToString:@"public.heic"]) {
            isHEIF = YES;
            *stop = YES;
        }
    }];
} else {
    NSString *UTI = [phAsset valueForKey:@"uniformTypeIdentifier"];
    isHEIF = [UTI isEqualToString:@"public.heif"] || [UTI isEqualToString:@"public.heic"];
}
下面这个方法不准确
[[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
    //这个dataUTI只是根据文件扩展名传过来的,不准确
}];
转换
方法一:有损
既然我们可以前置识别了,那么针对HEIF可以选择通过requestImageDataForAsset:phAsset获取到UIImage,再用UIImageJPEGRepresentation转为NSData,不过转为UIImage之后,图片的其他信息(Exif、GPS等)就丢失了。
方法二:无损
[[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:nil resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) {
    if (isHEIF) {
        CIImage *ciImage = [CIImage imageWithData:imageData];
        CIContext *context = [CIContext context];
        NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
    } else {
    }
}];
方法三:无损
if (isHEIF) {
    [phAsset requestContentEditingInputWithOptions:nil completionHandler:^(PHContentEditingInput * _Nullable contentEditingInput, NSDictionary * _Nonnull info) {
        if (contentEditingInput.fullSizeImageURL) {
            CIImage *ciImage = [CIImage imageWithContentsOfURL:contentEditingInput.fullSizeImageURL];
            CIContext *context = [CIContext context];
            NSData *jpgData = [context JPEGRepresentationOfImage:ciImage colorSpace:ciImage.colorSpace options:@{}];
        }
    }];
}
UIImage加载HEIF
CIImage *ciImage = [CIImage imageWithContentsOfURL:url];
imageView.image = [UIImage imageWithCIImage:ciImage];
这个方法有点慢,也可以使用CGImageSourceCreateWithURL和CGImageSourceCreateImageAtIndex加载
2018-04-25 22:19:42 u010417491 阅读数 699

在IOS开发中,最常见的功能之一就是地图定位功能,不单单是百度地图,高德地图等专业的地图导航软件,还有美团,咕咚等一些美食购物类和运动类也需要这样的功能,所以学会这项技能是一名IOS开发工程师必须的。

百度地图
咕咚
�美团
分享一些比较基础的关于定位方面的小知识.

关于定位有两个框架
1.CoreLocation ---->用于地理定位
2.Map Kit ---->用于地图展示

两个热词:

LBS: location based service
SLM: social local mobile

使用CoreLocation定位

首先在之前需要导入corelocation框架,然后在头文件导入corelocation.h头文件.
注意:coordinate是坐标,latitude是纬度,longitude是经度.

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 1.创建位置管理者
    CLLocationManager *locationManager = [[CLLocationManager alloc] init];
    self.locationManager = locationManager;
    // 在iO8之前,只要导入CoreLocation 会自动申请权限
    // 在iOS8之后需要程序员手写
    
    // 2.请求用户授权    必须要配置info.plist文件
    //在info里面配置NSLocationAlwaysUsageDescription或者
    //NSLocationWhenInUseUsageDescription
    // 请求app始终授权  无论程序在前台还是在后台运行  都可以使用定位
//    [locationManager requestAlwaysAuthorization];
    // 请求app在使用期间授权   在前台使用时才可以使用定位
    [locationManager requestWhenInUseAuthorization];
    
    if ([UIDevice currentDevice].systemVersion.floatValue >= 9.0) {
        // 临时开启后台定位  配置info.plist文件  不配置直接崩溃
        locationManager.allowsBackgroundLocationUpdates = YES;
    }
    // 3.设置属性(两个属性是为了让程序可以持续的进行定位)
//    // 距离筛选  单位:米  当用户移动100.5米后调用定位方法
//    locationManager.distanceFilter = 100.5;
//    // 期望精度  单位:米  系统默认将100米范围内作为一个位置
//    locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    // 4.设置代理
    locationManager.delegate = self;
    // 5.开启定位
    [locationManager startUpdatingLocation];
    // 开始更新移动方向
//    [locationManager startUpdatingHeading];


//代理方法,一旦开启定位,会自动调用这个代理方法
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    // 获取数据
//    NSLog(@"%@",locations);
    // 停止定位  省电
//    [manager stopUpdatingLocation];
}



// 比较位置的距离  比较的是两点之间的直线距离
- (void)compareDistance
{
    // 北京的位置
    CLLocation *location = [[CLLocation alloc] initWithLatitude:39 longitude:115];
    // 上海的位置
    CLLocation *location1 = [[CLLocation alloc] initWithLatitude:30 longitude:120];
    // 比较北京到上海的位置(直线距离)
    double distance = [location distanceFromLocation:location1];
    // 单位:米
    NSLog(@"%f",distance / 1000);
}
    
使用MapKit定位

修改地图类型 mapView.mapType
地图实时交通状态 mapView.showsTraffic
设置用户跟踪模式 mapView.userTrackingMode
代理方法,
//显示在地图中用户定位的位置

-(void)mapView:(MKMapView\*)mapView didUpdateUserLocation:(MKUserLocation \*)userLocation

//获取实时地图变化的区域变化(中心点,区域跨度)

-(void)mapView:(MKMapView \*)mapView regionDidChangeAnimated:(BOOL)animated

注意:这里需要导入的是MapKit框架和MapKit.h头文件.

- (void)viewDidLoad {
    [super viewDidLoad];
     
    // 修改地图类型
    /*
     MKMapTypeStandard    标准(默认)
     MKMapTypeSatellite   卫星
     MKMapTypeHybrid      混合
     MKMapTypeSatelliteFlyover  在中国暂时不能使用
     MKMapTypeHybridFlyover  在中国暂时不能使用
     */
    self.mapView.mapType = MKMapTypeStandard;
    
    // 实时交通状况 iOS9新增
    self.mapView.showsTraffic = YES;
    
    // 创建位置管理者
    self.locationManager = [[CLLocationManager alloc] init];
    // 请求用户授权  配置info.plist
    [self.locationManager requestWhenInUseAuthorization];
    // 设置用户的跟踪模式
    /*
     MKUserTrackingModeFollow  跟踪用户的位置   MKUserTrackingModeFollowWithHeading  跟踪用户的位置和方向
     */
    self.mapView.userTrackingMode = MKUserTrackingModeFollow;
    
    // 设置代理
    self.mapView.delegate = self;
}

// 跟踪到用户位置时调用
// mapView:地图
// userLocation:用户位置的大头针模型
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
    // 1.反地理编码
    // 1.1创建地理编码对象
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    // 1.2反地理编码
    [geocoder reverseGeocodeLocation:userLocation.location completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
        // 1.3防错处理
        if (error) {
            NSLog(@"%@",error);
            return ;
        }
        // 1.4获取地标
        CLPlacemark *placemark = [placemarks firstObject];
        // 2.给标题和子标题赋值
        userLocation.title = placemark.locality;
        userLocation.subtitle = placemark.name;
    }];
}


// 回到当前用户的位置
- (IBAction)backToCurrentLocation
{
    
    // 获取当前的跨度
    MKCoordinateSpan span = MKCoordinateSpanMake(0.024967, 0.015407);
    // 设置回到用户刚开始的区域 region(结构体) --1.中心点经纬度(结构体)--> 经度和纬度  2.经纬度跨度(结构体)-->经度跨度和纬度跨度
    // 设置区域并使用动画
    [self.mapView setRegion:MKCoordinateRegionMake(self.mapView.userLocation.location.coordinate, span) animated:YES];
}


- (IBAction)biggerMap
{
    // 修改经纬度跨度
    CGFloat latitudeDelta = self.mapView.region.span.latitudeDelta * 0.5;
    CGFloat longitudeDelta = self.mapView.region.span.longitudeDelta * 0.5;
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
    // 确定放大地图后的区域
    [self.mapView setRegion:MKCoordinateRegionMake(self.mapView.centerCoordinate, span) animated:YES];
}
- (IBAction)smallerMap
{
    // 修改经纬度跨度
    CGFloat latitudeDelta = self.mapView.region.span.latitudeDelta * 2;
    CGFloat longitudeDelta = self.mapView.region.span.longitudeDelta * 2;
    MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
    [self.mapView setRegion:MKCoordinateRegionMake(self.mapView.centerCoordinate, span) animated:YES];
}

演示

效果演示

说到底,其实苹果官方的框架已经做得不错了,该有的功能基本都具备,而且使用起来不是怎么困难,掌握起来也非常快.我这里只是分享一些比较基础的功能,欢迎工程师们赐教.
另外附上地理编码的小演示.

地理编码.gif
2018-07-16 10:06:12 saw471 阅读数 974
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.view.backgroundColor= [UIColor blackColor];
    
    UILabel *label = [[UILabel alloc]initWithFrame:CGRectMake(10, 0, CGRectGetWidth([UIScreen mainScreen].bounds)-20, 200)];
    label.numberOfLines = 0;
    NSMutableArray *arr = [NSMutableArray array];
    [arr addObject:@"气象通知:\n"];
    [arr addObject:@"今天的雨下的有点大"];
    [arr addObject:@"今天的雨下的比依萍要钱的那天还要大"];
    label.attributedText = [self attributedImageName:@"001" imageFram:CGRectZero arrStr:arr];
    [self.view addSubview:label];
    
    
}

#pragma mark ----------------------- 富文本标题 ------------------------
-(NSAttributedString*)attributedImageName:(NSString *)imageName  imageFram:(CGRect)imageFram   arrStr:(NSMutableArray *)arrstr
{
    //创建富文本
    NSMutableAttributedString *atring = [[NSMutableAttributedString alloc]init];
    for (int i = 0; i< arrstr.count; i++)
    {
        UIColor *color;
        if (i == 0)
        {
            color = [UIColor redColor];
        }
        else if (i == 1)
        {
            color = [UIColor greenColor];
        }
        else
        {
            color = [UIColor blueColor];
        }
        NSString *str = [NSString stringWithFormat:@"%@",arrstr[i]];
        NSMutableAttributedString *attri = [[NSMutableAttributedString alloc] initWithString:str];
        [attri addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0,str.length)];
        [atring appendAttributedString:attri];
    }
    
    // NSTextAttachment可以将要插入的图片作为特殊字符处理
    NSTextAttachment *attch = [[NSTextAttachment alloc] init];
    // 定义图片内容及位置和大小
    attch.image = [UIImage imageNamed:imageName];
    if (CGRectGetWidth(imageFram) > 0)
    {
        attch.bounds = imageFram;
    }
    else
    {
        attch.bounds = CGRectMake(0, -1, 17, 17);
    }
    //创建带有图片的富文本
    NSAttributedString *stringIm = [NSAttributedString attributedStringWithAttachment:attch];
    //将图片放在第一位
    [atring insertAttributedString:stringIm atIndex:0];
    return atring;
}

2015-08-21 12:33:56 u014406672 阅读数 1596

开发环境:Xcode6.4

模拟器  : IOS8.4

OS X : 10.0.4

小编博客链接: http://www.goofyy.com

首先例子是小编写的一个定位获取经纬度,然后在地图上面显示,并自定义大头针的一个程序。先上图


首先说一下定位,在 iOS 8 之前,位置服务的权限是二元的:你要么赋予一个应用得到使用位置服务的权限,要么不给。你可以在 Settings.app 查看哪些 app 可以在后台取得你的位置信息,但除了完全不让这个 app 使用位置服务之外,你不能做任何的事来阻止它获取位置信息,但是在IOS8之后, 修改了这个问题,ISO8把应用程序分成两个权限,

“使用期间”  正如标题,程序在使用期间会获取你的位置信息。
“始终”   这个就跟IOS8之前一样,会在程序中一直获取你的个人信息。


所以我们在使用地图的时候,要在Info.plist里面添加两行文字,设置我们程序使用地图的权限。

Screen Shot 2015-08-18 at 5.27.16 PM

NSLocationWhenInUseUsageDescription  //用的时候获取位置

NSLocationAlwaysUsageDescription    //始终获取用户位置

后面的value 可填写或不填写。value是在获取用户定位允许的弹窗信息。如果没有这两行东东,那么程序不会提醒用户获取定位允许,那么你的程序也一直没办法获取定位。明白了之后,就开始写程序吧。


首先就是先把CoreLocation框架引入过来。直接晒代码吧。懒得写了。代码下面注释

//
//  ViewController.swift
//  获取路线
//
//  Created by goofygao on 8/18/15.
//  Copyright (c) 2015 goofyy. All rights reserved.
//

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController,MKMapViewDelegate,CLLocationManagerDelegate {
    @IBOutlet weak var mapView: MKMapView!
    var locationManger:CLLocationManager = CLLocationManager()
    var location:CLLocation!
    var ann:MKPointAnnotation = MKPointAnnotation()
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationManger.delegate = self
        locationManger.desiredAccuracy = kCLLocationAccuracyBest
        locationManger.distanceFilter = kCLLocationAccuracyKilometer
        
        locationManger.requestAlwaysAuthorization()
        locationManger.startUpdatingLocation()
        
        mapView.delegate = self
        mapView.mapType = MKMapType.Satellite
        
        ann.title = "定位的位置"
        ann.subtitle = "广州"
        
        mapView.addAnnotation(ann)
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    /**
    
    重写 - 更改大头针颜色
    :param: mapView
    :param: annotation
    
    :returns: MKAnnotationView
    */
    func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!
    {
        var view:MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
        view.pinColor = MKPinAnnotationColor.Red
        //view.image = UIImage(named: "localtion.png")
        var viewLeft = UIView(frame: CGRectMake(0, 0, 50, 50))
        viewLeft.backgroundColor = UIColor.redColor()
        var viewRight = UIView(frame: CGRectMake(0, 0, 50, 50))
        viewRight.backgroundColor = UIColor.greenColor()
        view.leftCalloutAccessoryView = viewLeft
        view.rightCalloutAccessoryView = viewRight
        view.draggable = true
        view.canShowCallout = true
        return view
    }
    
   
    
    func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
        location = locations.last as! CLLocation
        if((location) == nil) {
            locationManger.startUpdatingLocation()
        }
        println("\(location.coordinate.longitude)")
        mapView.region = MKCoordinateRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), span: MKCoordinateSpanMake(20, 20))
        ann.coordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
    }

}

分开来说,首先是定位的问题。添加CLLocationManagerDelegate代理,实现代理的方法

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { }


这个方法是在获取到手机的位置的时候调用。


        locationManger.delegate = self
        locationManger.desiredAccuracy = kCLLocationAccuracyBest
        locationManger.distanceFilter = kCLLocationAccuracyKilometer
        
        locationManger.requestAlwaysAuthorization()
        locationManger.startUpdatingLocation()

设置代理为当前,设置定位的精度和开始定位。


然后到了设置地图地方了。添加地图的代理,设置大头针的主标题和副标题。

mapView.delegate = self
        mapView.mapType = MKMapType.Satellite
        
        ann.title = "定位的位置"
        ann.subtitle = "广州"
        
        mapView.addAnnotation(ann)


大头针的默认显示颜色为红色。然后我们可以重写一下大头针的方法,来重绘一下大头针


func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView!
    {
        var view:MKPinAnnotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
        view.pinColor = MKPinAnnotationColor.Red
        //view.image = UIImage(named: "localtion.png")
        var viewLeft = UIView(frame: CGRectMake(0, 0, 50, 50))
        viewLeft.backgroundColor = UIColor.redColor()
        var viewRight = UIView(frame: CGRectMake(0, 0, 50, 50))
        viewRight.backgroundColor = UIColor.greenColor()
        view.leftCalloutAccessoryView = viewLeft
        view.rightCalloutAccessoryView = viewRight
        view.draggable = true
        view.canShowCallout = true
        return view
    }


设置大头针和地图定位的经纬度,因为经纬度是在CLLocationManagerDelegate协议的实现方法中获取到,所以我们在它的协议方法里使用。


location = locations.last as! CLLocation
        if((location) == nil) {
            locationManger.startUpdatingLocation()
        }
        println("\(location.coordinate.longitude)")
        mapView.region = MKCoordinateRegion(center: CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude), span: MKCoordinateSpanMake(20, 20))
        ann.coordinate = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
    }

设置了大头针的经纬度和定位的经纬度,和地图显示的范围。

然后看下一个。

地图覆盖层


简单来说就是在地图地图上面画图。

首先是在地图上面画线

        var coor = [CLLocationCoordinate2D]()
        for (var i=0; i<5; i++) {
         po = CLLocationCoordinate2DMake(CLLocationDegrees(23 + i), 113)
            coor.append(po)
        }
        var line = MKPolyline(coordinates: &coor, count: 5)
        mapView.addOverlay(line)


这里有一个犯错点,var line =MKPolyline(coordinates: &coor, count:5)  。

 MKPolyline(coordinates: <#UnsafeMutablePointer<CLLocationCoordinate2D>#>, count: <#Int#>)


不少人并不知道<#UnsafeMutablePointer<CLLocationCoordinate2D>#>这货是什么卵类型。说白了就是一个指针。从oc过来的大部分人都应该知道,因为oc在存储上面for循环生成的几个经纬度的时候,通常采用的是申请一部分内存,然后放进去。采用了C的语法。so下面直接引用了指针。指向存储经纬度空间的内存。这里也就是这个数组的地址。加个“&”即可。


然后添加 MKMapViewDelegate 代理,实现代理的方法。

func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer! {
        var render = MKPolylineRenderer(overlay: overlay)
        render.lineWidth = 3
        render.strokeColor = UIColor.redColor()
        return render
        
    }


这里会自动调用代理的方法。搞到这里的时候,运行,一条直线也就出来了。下面是两个项目的工程,放在了github上


完整项目 https://github.com/goooooooofy/originMapApple.git




没有更多推荐了,返回首页