使用场景【澳门葡京游戏】,iOS源代码分析

作者:澳门新葡京平台游戏

之前写过一片AVOS一些常用的使用, 比如用户注册, 登录, 数据的查询, 图片的加载以及初始化AVOS使用解析, 慢慢的在自己玩一些东西的过程中发现AVOS确实是一个不错的后端支撑, 简称Baas, 移动应用后端服务。

runtime的功能很强大,包含的的内容也很多,见下图

一直以为能够读懂源代码是件很牛的事情,但是每次都被动辄复杂的语法的架构吓跑,在偶然看到一个叫Draveness的大牛写的源代码分析博客,耐着性子看完了一篇SDWebImage框架的分析,才发觉其实啃源代码没那么可怕,而且对于功力的提升十分显著,尤其偶尔接触到的底层的理解让我豁然开朗,遂打算独自写一篇第三方框架的源代码分析作为自己的第一篇技术博客.

什么是CoreData

所以在慢慢的开发过程中, 使用RAC以及AVOS快速的建立一套登录体系, 以及数据的Fetch, 云代码的自定义与调用, AVObject与本地Model的相互转换也慢慢的熟悉了起来。

澳门葡京游戏 1

MJExtension

A fast, convenient and nonintrusive conversion between JSON and model.

MJExtension是一套字典和模型之间互相转换的超轻量级框架.

  • CoreData 不是一个数据库但是可以使用数据库来存储数据,也可以使用其他方式,比如:数据库文件,XML,二进制文件,内存等。CoreData 提供了 对象-关系映射(ORM) 功能。能够实现数据库数据和 OC 对象的相互转换,在这个转换过程中我们不需要编写任何 SQL 语句。

  • 可以简单的理解为Cocoa对SQLite的一层封装

代码浅显易懂, 所以不做过多的解释了。

但是我们平时项目中使用的并不是很多,以下是几种常见的场景:

能做什么

  • 字典(JSON)--> 模型(Model) CoreData模型(Core Data Model)
  • JSON字符串(JSONString) --> 模型(Model)、CoreData模型(Core Data Model)
  • 模型(Model)、CoreData模型(Core Data Model) --> 字典(JSON)
  • JSON数组(JSON Array) --> 模型数组(Model Array)、CoreData模型数组(Core Data Model Array)
  • JSON字符串(JSONString) --> 模型数组(Model Array)、CoreData模型数组(Core Data Model Array)
  • 模型数组(Model Array)、CoreData模型数组(Core Data Model Array) --> 字典数组(JSON Array)
  • 只需要一行代码,就能实现模型的所有属性进行Coding(归档和解档)

为什么要使用CoreData

  1. Model - AVObject的相互转换
    • 为了后期把服务切到自己的服务器上来, 所以初期我们不要直接使用AVObject进行操作, 而是自己写Model, 与AVObject进行相互转换。这里的Model是继承JSONModel来写的, 这里JSON与实体的相互转换大家还可以使用MJExtension、Mantle等。实体的与JSON的转换大大提高了我们开发的效率, 也便于项目的扩展, 所以推荐大家使用。 团队人数足够的时候, 可以直接使用RestKit进行开发, 可以快速的部署并与服务器进行数据通信, 支持CoreData(插嘴:CoreData苹果自己都不用, 大家还是多看看SQL吧,所以我们依旧在用FMDB)。
1. 字典转换为模型。

通过网络接口获取的数据一般是 JSON 格式的,需要转为我们自定义的模型,方便使用。
定义BaseModel,所有模型的基类。
BaseModel.h

#import <Foundation/Foundation.h>

@interface BaseModel : NSObject

-(id)initWithDic:(NSDictionary *)dic;

@end

BaseModel.m

#import "BaseModel.h"
#import <objc/runtime.h>

@implementation BaseModel

-(id)initWithDic:(NSDictionary *)dic{
    //Class cls = [self class];
    unsigned int count = 0;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    for (int i=0; i<count; i  ) {
        objc_property_t property = properties[i];
        NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
        id value = [dic objectForKey:propertyName];
        if (!value) {
            continue;
        }
        [self setValue:value forKey:propertyName];

    }
    free(properties);
    return  self;
}


@end

定义数据模型Model
Model.h

#import "BaseModel.h"

@interface Model : BaseModel

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *sex;
@property (nonatomic, strong) NSNumber *age;

@end

Model.m

#import "Model.h"

@implementation Model

@end

声明Model的实例并使用

NSDictionary *dic = @{@"name": @"Brook",
                              @"sex": @"male",
                              @"age": @(10)};

Model *model = [[Model alloc] initWithDic:dic];
NSLog(@"model name=%@", model.name);

字典 -> 模型

MJExtension提供了一个类方法进行字典转模型的工作,我们通过对
(instancetype)mj_objectWithKeyValues:(id)keyValues方法解析,来开始本篇分析.下面让我们打开这个方法的实现代码NSObject MJKeyValue.m.

当然你也可以git clone github git@github.com:CoderMJLee/MJExtension.git到本地来看.

  (instancetype)mj_objectWithKeyValues:(id)keyValues
{
    return [self mj_objectWithKeyValues:keyValues context:nil];
}

使用这个类方法的唯一作用就是调用了另一个方法

  (instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context
{
    // 获得JSON对象
    keyValues = [keyValues mj_JSONObject];
    MJExtensionAssertError([keyValues isKindOfClass:[NSDictionary class]], nil, [self class], @"keyValues参数不是一个字典");

    if ([self isSubclassOfClass:[NSManagedObject class]] && context) {
        return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context];
    }
    return [[[self alloc] init] mj_setKeyValues:keyValues];
}

下面我们就仔细分析一下这个方法的实现过程.

  • 极大的减少Model层的代码量

  • 优化了使用SQLite时候的性能

  • 提供了可视化设计

BaseModel.h

2.Method Swizzling

在没有一个类的实现源码的情况下,想改变其中一个方法的实现,除了继承它重写、和借助类别重名方法暴力抢先之外,还有一个方法就是Method Swizzling.
Person.m

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

-(NSString *)run{
    return @"run";
}

-(NSString *)study{
    return @"study";
}

@end

Person.h

#import "Animal.h"

@interface Person : Animal

-(NSString *)run;
-(NSString *)study;

@end

上面是一般情况,调用结果如下:

澳门葡京游戏 2

image.png

添加Method Swizzling魔法,修改Person.m代码

#import "Person.h"
#import <objc/runtime.h>
@implementation Person

 (void)load1{
    Method methodRun = class_getInstanceMethod([self class], @selector(run));
    Method methodStudy = class_getInstanceMethod([self class], @selector(study));
    method_exchangeImplementations(methodRun, methodStudy);
}

-(NSString *)run{
    return @"run";
}

-(NSString *)study{
    return @"study";
}

@end

添加魔法后的调用结果:

澳门葡京游戏 3

image.png

两个方法进行了调用,著名下拉刷新第三方软件MJRefresh中使用过这个。

两个参数

  • (id)keyValues 用来接收传入的字典,将参数写为id类型是为了能够接收所有类型的参数
  • (NSManagedObjectContext *)context (NSManagedObjectContext)是一个对于数据库的封装,只要能保存在数据库中的内容,都可以保存在NSManagedObjectContext中.

CoreData框架

#import "JSONModel.h"@interface BaseModel : JSONModel/// Adapter model -> AVObject- (AVObject *)toAVObject;/// Initialized with AVObject- (instancetype)initWithAVObject: (AVObject *)object;/// Initialized with avClassName- (instancetype)initWithClassName: (NSString *)avClassName;//! @abstract AV ClassName@prop_strong(NSString *, avClassName);@end

获取对象

方法的第一步是接收传入的对象

- (id)mj_JSONObject
{
    if ([self isKindOfClass:[NSString class]]) {
        return [NSJSONSerialization JSONObjectWithData:[((NSString *)self) dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:nil];
    } else if ([self isKindOfClass:[NSData class]]) {
        return [NSJSONSerialization JSONObjectWithData:(NSData *)self options:kNilOptions error:nil];
    }

    return self.mj_keyValues;
}

如果传入对象是NSString类型或者NSData类型,会使用系统自带的数据类型转换将对象转换成JSON类型返回,否则返回自己.

澳门葡京游戏 4

BaseModel.m

构建错误

第二行代码使用了一个自定义的方法MJExtensionAssertError

#define MJExtensionAssertError(condition, returnValue, clazz, msg) 
[clazz setMj_error:nil]; 
if ((condition) == NO) { 
    MJExtensionBuildError(clazz, msg); 
    return returnValue;
}

通过第一步的转换,传入的对象会是JSON类型或其他类型的一种,如果传入的不是JSON类型,MJExtensionBuildError会调用runtime中的objc_setAssociatedObject方法为当前类关联一个NSError对象,用来生成错误日志.
在庞大的项目中难免会遇到传值错误类型的低级错误,这个方法可以让用户在debug的过程中准确找出错误位置并进行修改.
这里作者为clazz这个参数的定义是[self class],即自身类别.

CoreData

#import "BaseModel.h"@implementation BaseModel  propertyIsOptional:(NSString *)propertyName { return YES;}/// Adapter model -> AVObject- (AVObject *)toAVObject { if (!self.avClassName) { return nil; } AVObject * object = [AVObject objectWithClassName:self.avClassName]; for (NSString * attributeName in [self classAttributesArray]) { id value = [self valueForKey:attributeName]; if  { [object setObject:value forKey:attributeName]; } } NSLog(@"%@", object); return object;}/// Initialized with AVObject- (instancetype)initWithAVObject: (AVObject *)object { self = [super init]; if  { for (NSString * attributeName in [self classAttributesArray]) { id value = [object objectForKey:attributeName]; if  { [self setValue:value forKey:attributeName]; } } } return self;}- (instancetype)initWithClassName:(NSString *)avClassName { self = [super init]; if  { self.avClassName = avClassName; } return self;}@end

context参数处理

接下来会进行context参数的处理

if ([self isSubclassOfClass:[NSManagedObject class]] && context) { return [[NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass(self) inManagedObjectContext:context] mj_setKeyValues:keyValues context:context]; }

如果调用此方法的类别为NSManagedObject的子类而且传入的context不为空,则会实例一个NSEntityDescription对象重新进行类型转换.


在上边用到了 [self classAttributesArray]下边给出这个方法的内容, 运行时获取类的属性名称, 这个方法之前在Hack融云输入框的文章中有用到, 并很详细。

实例化对象

return [[[self alloc] init] mj_setKeyValues:keyValues];

最后实例化一个self类型的对象进行类型转换操作.


以上行为我称之为是对参数的预处理,只有传入正确或者通过处理后能够进行类型转换的参数后才能够正确的进行类型转换方法.

  • .xcdatamodeld 文件:定义了数据库数据和 OC 对象转换的映射关系,编译后为 .momod 文件

  • NSManagedObjectModel:负责读取解析 .momod 文件

  • NSPersistentStoreCoordinator:通过解析结果去实现数据库和 OC 对象之间的相互转换,主要是操作数据库的,我们一般用不上,由系统处理

  • NSManagedObjectContext:等同于一个容器,用来存储从数据库中转换出来的所有的 OC 对象。我们的增删改查操作直接对这个类使用来获得或者修改需要的 OC 对象,它能够调用 NSPersistentStoreCoordinator 类实现对数据库的同步

  • NSManagedObject:数据库中的数据转换而来的OC对象

NSObject

类型转换

(instancetype)mj_objectWithKeyValues:(id)keyValues context:(NSManagedObjectContext *)context最后一步进入类型转换处理,在这里进行的是JSONModel行为.

- (instancetype)mj_setKeyValues:(id)keyValues context:
(NSManagedObjectContext *)context```
由于这个方法的实现代码太长,在这里就不再贴出全部代码,后文会挑选关键代码进行分析.

*注:
1. 一旦数据创建完毕,就不能再修改.xcdatamodeld文件,如果有修改,必须删除数据库重新创建,否则打开数据库已定会失败。 去沙盒路径下把创建的数据库删除即可
2. 不能使用alloc init来创建对象

- (NSMutableArray *)classAttributesArray { NSString *className = NSStringFromClass([self class]); const char * cClassName = [className UTF8String]; id classM = objc_getClass(cClassName); unsigned int outCount, i; objc_property_t * properties = class_copyPropertyList(classM, &outCount); NSMutableArray * array = [NSMutableArray array]; for (i = 0; i < outCount; i  ) { objc_property_t property = properties[i]; NSString * attributeName = [NSString stringWithUTF8String:property_getName]; [array addObject:attributeName]; } return array;}

  1. 自己写操作合集, 而不是直接调用.
    • 建议在使用AVOS的时候自己封装一下操作, 而不是在使用的地方直接调用, 因为项目后期肯定是要迁移到自己的Server上的, 所以这样封装后, 在准备迁移的时候更改方法体即可。这里只给出简单的登录注册以及验证码验证等操作.
AppDelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow * window;

/**
  * 上下文  容器  
  * 存放的是 所有从数据库中取出的转换成OC对象
  */
@property (readonly, strong, nonatomic) NSManagedObjectContext * managedObjectContext;

/* 读取解析 .momd文件中的内容 */
@property (readonly, strong, nonatomic) NSManagedObjectModel * managedObjectModel;

/* 连接的类,处理数据库数据和OC数据底层的相互转换 */
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator * persistentStoreCoordinator;

/* 保存 */
-(void)saveContext;

/* 获取沙盒路径 */
-(NSURL *)applicationDocumentsDirectory;

@end

AVOSOperate.h

AppDelegate.m
#import "AppDelegate.h"
#import "People.h"

@interface AppDelegate ()
@end

@implementation AppDelegate

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSLog(@"沙盒路径路径:%@",[self applicationDocumentsDirectory].absoluteString);

    NSLog(@"%@",self.managedObjectContext);


    //插入一条数据 (往People表中插入一条数据)
    //NSEntityDescription 实体类
    //EntityForName 实体名称(表名)
    People * p = [NSEntityDescription insertNewObjectForEntityForName:@"People" inManagedObjectContext:self.managedObjectContext];
    //赋值
    p.name = @"李四";
    p.age = @(25);
    p.phone = @"13667895678";
    //同步操作  把context中的数据同步到数据库中
    [self saveContext];



    // 查询数据
    // 创建查询请求
    NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"People"];
    // Context 执行请求(执行查询操作) 数组中存放的是oc类的对象(People类的对象)
    NSArray * array = [self.managedObjectContext executeFetchRequest:request error:nil];
    for (People *people in array)
    {
       NSLog(@"%@",people.name);
    }


    //查询特定条件数据  (年龄>20)
    NSFetchRequest * request1 = [NSFetchRequest fetchRequestWithEntityName:@"People"];
    //使用谓词指定查询的判定条件
    NSPredicate * predicate = [NSPredicate predicateWithFormat:@"SELF.age > 20"];
    //关联判定条件
    [request1 setPredicate:predicate];
    //执行查询操作
    NSArray * array2 = [self.managedObjectContext executeFetchRequest:request1 error:nil];
    for (People * people in array2)
    {
        NSLog(@"%@",people.age);
    }



    //更改数据
    //获取出要修改的数据
    People * people2 = [array lastObject];
    //修改属性
    people2.name = @"123";
    people2.age  = @(30);
    //同步数据
    [self saveContext];



    //删除数据
    People * people3 = [array lastObject];
    [self.managedObjectContext deleteObject:people3];
    //同步数据
    [self saveContext];

    return YES;
}

//点击HOME键程序直接退出
-(void)applicationWillTerminate:(UIApplication *)application
{
    [self saveContext];
}

#pragma mark - Core Data stack

@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;

-(NSURL *)applicationDocumentsDirectory
{
    //获取沙盒路径下documents文件夹的路径 NSURL   (类似于search)
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

//managedObjectModel 属性的getter方法
-(NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) return _managedObjectModel;

    //.xcdatamodeld文件 编译之后变成.momd文件  (.mom文件)
    NSURL * modelURL = [[NSBundle mainBundle] URLForResource:@"CoreData_Class" withExtension:@"momd"];

    //把文件的内容读取到managedObjectModel中
    _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    return _managedObjectModel;
}

//Coordinator 调度者负责数据库的操作 创建数据库 打开数据 增删改查数据
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;

    //根据model创建了persistentStoreCoordinator
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    // 设置数据库存放的路径
    NSURL * storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreData_Class.sqlite"];

    NSError * error = nil;

    //如果没有得到数据库,程序崩溃
    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
    {
        NSLog(@"错误信息: %@, %@", error, [error userInfo]);
        abort(); //崩溃
    }

    return _persistentStoreCoordinator;
}

//容器类 存放OC的对象
-(NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil)  return _managedObjectContext;

    NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
    if (!coordinator)
    {
        return nil;
    }

    //创建context对象
    _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

    //让context和coordinator关联   context可以对数据进行增删改查功能
    [_managedObjectContext setPersistentStoreCoordinator:coordinator];

    return _managedObjectContext;
}

#pragma mark - Core Data Saving support

-(void)saveContext
{
    NSManagedObjectContext * managedObjectContext = self.managedObjectContext;
    if (managedObjectContext != nil)
    {
        NSError * error = nil;

        // hasChanges 判断数据是否更改
        // sava 同步数据库中的数据
        if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
        {
            NSLog(@"错误信息: %@, %@", error, [error userInfo]);
            abort();
        }
    }
}

@end
@interface AVOSOperate : NSObject/// Load AVOS  LoadAVOS;/// Login  LoginWithNumber: (NSString *)number passWord: (NSString *)passWord;/// Regist  RegisterWithNumber: (NSString *)number passWord: (NSString *)passWord nickName: (NSString *)nickName;/// Verify  VerifyNumber: (NSString *)number;@end
People.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@interface People : NSManagedObject

@property (nonatomic, retain) NSNumber * age;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSString * phone;

@end

澳门葡京游戏,AVOSOperate.m

People.m
#import "People.h"

@implementation People

/**
 * @property    描述对应@synthesize和@synamic两个关键字
 * @synthesize  会生成属性的setter,getter方法
 * @dynamic     不生成属性的setter,getter方法
 * 两个都没有写,默认是@synthesize
 */

@dynamic age;
@dynamic name;
@dynamic phone;

@end

参考文献

  • iOS CoreData介绍和使用
  • 关于CoreData的增 删 改

微信公共号:iapp666666
GitHub:点此前往

#import "AVOSOperate.h"@implementation AVOSOperate  LoadAVOS { [AVOSCloud setApplicationId:@"0ypwnkwb9bl5vq3y9uplcy7luxow37sbjfwg31ni2swplksn" clientKey:@"gswb6dos30r6wojks6ifmxxs1r59d2pwnp5wryrwem0dztmr"]; [AVOSCloud useAVCloudCN]; #pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations" [AVOSCloud registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound) categories:nil]; #pragma clang diagnostic pop}  LoginWithNumber: (NSString *)number passWord: (NSString *)passWord { NSLog(@"%@ - %@", number, passWord); [AVUser logInWithMobilePhoneNumberInBackground:number password:passWord block:^(AVUser *user, NSError *error) { if  { [LoginManager sharedInstance].isLogin = YES; [[LoginManager sharedInstance] Record:number pass:passWord]; } else { [DLOperation sharedInstance].shake = YES; [SVProgressHUD showErrorWithStatus:[error localizedDescription]]; } }];}  RegisterWithNumber: (NSString *)number passWord: (NSString *)passWord nickName: (NSString *)nickName { AVUser * user = [AVUser user]; user.username = number; user.password = passWord; user.mobilePhoneNumber = number; [user setObject:nickName forKey:@"nickName"]; [user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) { if (succeeded) { [LoginManager sharedInstance].isLogin = YES; [[LoginManager sharedInstance] Record:number pass:passWord]; [LoginManager sharedInstance].isSendVerifyCode = YES; } else { [DLOperation sharedInstance].shake = YES; [SVProgressHUD showErrorWithStatus:[error localizedDescription]]; } }];}  VerifyNumber: (NSString *)number { [AVUser verifyMobilePhone:number withBlock:^(BOOL succeeded, NSError *error) { if (succeeded) { [LoginManager sharedInstance].VerifySucceed = YES; } else { [DLOperation sharedInstance].shake = YES; [SVProgressHUD showErrorWithStatus:[error localizedDescription]]; } }];}@end

在上边代码中用到的类似这样的值[LoginManager sharedInstance].isLogin = YES;是为了RAC的方便。在界面中我对操作结果进行监听。

LoginViewController.m

- LoginAction { // Login Success, Set Login Yet [self.view endEditing:YES]; if ([self AuthText:_userNameText.text] && [self AuthText:_passWordText.text]) { [[LoginManager sharedInstance] Login:_userNameText.text pass:_passWordText.text]; @weakify; [SVProgressHUD showWithStatus:@"正在登录..." maskType:SVProgressHUDMaskTypeClear]; [[RACObserve([LoginManager sharedInstance],isLogin )filter:^BOOL(NSNumber *value) { return value.floatValue == TRUE; }]subscribeNext:^(NSNumber * x) { @strongify [self.navigationController presentViewController:(UIViewController *)[DLOperation sharedInstance].tabBar animated:YES completion:nil]; [self.navigationController dismissViewControllerAnimated:YES completion:nil]; [SVProgressHUD showSuccessWithStatus:@"登录成功"]; }]; } else { [self.view shakeView]; }}

RAC的使用方法这里不做讲解, 下篇文章会写RAC的使用以及小技巧以及iOS9.0的一些新特性并给出Demo, 像3DTouch之类, GitPage我已经把代码Fork到手, 慢慢的做详细的讲解, iOS9.0的适配相信大家已经看过不少, 这里不多嘴舌了。并且教大家制作快速的监听器, 其实之前的文章DLObserver使用的就是一些这其中的小技巧。学无止境, 多看大牛。

另外, 在验证AVOS速度不错的时候, 也使用了一些小代码片段, 有一段是计算这个方法走了多久的、 不过仅同步有效, 异步需要自己写一下。

double a = CFAbsoluteTimeGetCurrent;double b = CFAbsoluteTimeGetCurrent();unsigned int m =  * 1000.0f); // convert from seconds to milliseconds}

3.CLLocation自己封装的使用- 位置的使用相信大家可以在百度或者Google上边招到很多的代码, 所以这里不做过多的解释, 直接把代码扔出来大家看吧。 里边包括了位置编解码、计算路线等操作。

DLLocationManager.h

//// DLLocationManager.h// //// Created by XueYulun on 15/7/10.///////----------------------------------/// @name 位置管理///----------------------------------/* 1. NSLocationAlwaysUsageDescription 2. NSLocationWhenInUseUsageDescription *///! @name 参考文献: http://blog.csdn.net/weisubao/article/details/43205229 大头针的自定义, 划线.typedef NS_ENUM(NSInteger, DLLocationReques) { DLLocationReques_Always = 1UL << 0, DLLocationReques_WhenUse = 2UL << 1};#import <Foundation/Foundation.h>#import <CoreLocation/CoreLocation.h>#import <MapKit/MapKit.h>typedef void(^didUpdateLocation)(CLLocation * location, NSError * error);typedef void(^didGeocodeLocation)(NSDictionary * addressInfoDict, NSError * error);typedef void(^didGeocodeAddress)(CLPlacemark * placeMark, NSError * error);@interface DLLocationManager : NSObject <CLLocationManagerDelegate>@prop_strong(CLLocationManager *, locationManager); // 定位器@prop_strong(CLGeocoder *, geocoder); // 解码器@prop_strong(CLPlacemark *, placemark); // 最近的一次解码结果@singleton(DLLocationManager);- UpdateLocationWithAccuracy: (CLLocationAccuracy)accuracy Update:(DLLocationReques)requestType CompleteBlock: (didUpdateLocation)locationBlock;// CLLocation对象 - 具体定位信息字典- GeocodeWithLocation: (CLLocation *)Location CompleteBlock: (didGeocodeLocation)geocodeBlock;// NSString位置 - CLPlacemark, 可用于添加大头针, 计算线路, 划线等. 一次只能对一个位置进行编码。- GeocodeAddressString: (NSString *)Place CompleteBlock: (didGeocodeAddress)geocodeBlock;- GeocodeAddressString:(NSString *)Place WithRegion:(CLRegion *)region CompleteBlock:(didGeocodeAddress)geocodeBlock;// 2点之间的线路, 并且划线- MapView: (MKMapView *)mapView AddLineFrom: (CLPlacemark *)From to: (CLPlacemark *)To;@end

DLLocationManager.m

//// DLLocationManager.m// //// Created by XueYulun on 15/7/10.////#import "DLLocationManager.h"@interface DLLocationManager ()@prop_copy(didUpdateLocation, locationBlock);@end@implementation DLLocationManager@def_singleton(DLLocationManager);- UpdateLocationWithAccuracy: (CLLocationAccuracy)accuracy Update:(DLLocationReques)requestType CompleteBlock: (didUpdateLocation)locationBlock { self.locationBlock = locationBlock; self.locationManager.desiredAccuracy = accuracy; // iOS 8.0 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) { BOOL hasAlwaysKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil; BOOL hasWhenInUseKey = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil; requestType == DLLocationReques_Always ? [self.locationManager requestAlwaysAuthorization] : [self.locationManager requestWhenInUseAuthorization]; if (!hasAlwaysKey && !hasWhenInUseKey) { NSAssert(hasAlwaysKey || hasWhenInUseKey, @"在iOS 8.0 之后使用定位, 首先在INFO.plist文件中加入下面2项中的一项 NSLocationWhenInUseUsageDescription, NSLocationAlwaysUsageDescription."); } } [self.locationManager startUpdatingLocation];}- GeocodeWithLocation: (CLLocation *)Location CompleteBlock: (didGeocodeLocation)geocodeBlock { @weakify; [self.geocoder reverseGeocodeLocation:Location completionHandler:^(NSArray *placemarks, NSError *error) { @strongify; if  { self.placemark = [placemarks firstObject]; geocodeBlock(((CLPlacemark *)[placemarks firstObject]).addressDictionary, nil); } else { geocodeBlock(nil, error); } }];}- GeocodeAddressString: (NSString *)Place CompleteBlock: (didGeocodeAddress)geocodeBlock { @weakify; [self.geocoder geocodeAddressString:Place completionHandler:^(NSArray *placemarks, NSError *error) { @strongify; self.placemark = [placemarks firstObject]; geocodeBlock([placemarks firstObject], error); }];}- GeocodeAddressString:(NSString *)Place WithRegion:(CLRegion *)region CompleteBlock:(didGeocodeAddress)geocodeBlock { @weakify; [self.geocoder geocodeAddressString:Place inRegion:region completionHandler:^(NSArray *placemarks, NSError *error) { @strongify; self.placemark = [placemarks firstObject]; geocodeBlock([placemarks firstObject], error); }];}- MapView: (MKMapView *)mapView AddLineFrom: (CLPlacemark *)From to: (CLPlacemark *)To { // 设置方向请求 MKDirectionsRequest * request = [[MKDirectionsRequest alloc] init]; // 设置起点终点 MKPlacemark * sourcePm = [[MKPlacemark alloc] initWithPlacemark:From]; request.source = [[MKMapItem alloc] initWithPlacemark:sourcePm]; MKPlacemark * destiPm = [[MKPlacemark alloc] initWithPlacemark:To]; request.destination = [[MKMapItem alloc] initWithPlacemark:destiPm]; //定义方向对象 MKDirections * dirs = [[MKDirections alloc] initWithRequest:request]; //计算路线 [dirs calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) { DLogOut(@"总共有%lu条线路",(unsigned long)response.routes.count); for (MKRoute *route in response.routes) { [mapView addOverlay:route.polyline]; } }]; /* 划线以及颜色 -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay{ MKPolylineRenderer * renderer = [[MKPolylineRenderer alloc] initWithOverlay:overlay]; renderer.strokeColor = [UIColor redColor]; return renderer; } */}- (CLLocationManager *)locationManager { if (!_locationManager) { _locationManager = [[CLLocationManager alloc] init]; _locationManager.delegate = self; _locationManager.distanceFilter = 10; // 默认的定位服务更新频率, 米 } return _locationManager;}- (CLGeocoder *)geocoder { if (!_geocoder) { _geocoder = [[CLGeocoder alloc] init]; } return _geocoder;}#pragma mark - #pragma mark Location Did Update- locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations { CLLocation * currentLocation = [locations lastObject]; if (self.locationBlock) { self.locationBlock(currentLocation, nil); }}- locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error { if (self.locationBlock) { self.locationBlock(nil, error); }}@end

文中的weakify以及strongify为了避免block的循环引用, 详细解释以及代码实现可以在这里看到Weakify&Strongify, 这个写法只是最常见的写法, 不过ReactCocoa中给出了一种装逼的写法, 大家去看一下, 使用宏把代码片段连到一起。 巧妙的使用宏可以帮助我们大大的简化代码并提高逼格。

上班第一天, 祝大家开心。

CopyRight@Dylan 2015-10-8.

本文由新葡京8455发布,转载请注明来源

关键词: