AFNetworking的简单使用
最近看学习一些项目代码到了使用AFNetworking
的项目,所以去学习了一下,这里简单的总结一下,AFNetworking
的使用方法。
AFNetworking简介
AFNetworking
是一个很受大众欢迎的网络框架,可以帮助管理和处理网络任务请求,包括下载、上传、get
、post
请求等。
安装
AFNetworking
的安装可以使用CocoaPods
在文件中加入:
pod 'AFNetworking'
并执行 pod install
就可以了。有一点要注意的是最新版本为3.1
这个版本删除了基于NSURLConnectionOperation
的AFHTTPRequestOperationManager
的支持。转而使用基于NSURLSession
封装的AFHTTPSessionManager
。
网络监听
AFNetworking
提供了一个监听网络状态的方法,来实时的判断当前网络是否良好。具体代码如下:
// 如果要检测网络状态的变化,必须用检测管理器的单例的startMonitoring
/**
AFNetworkReachabilityStatusUnknown = -1, // 未知
AFNetworkReachabilityStatusNotReachable = 0, // 无连接
AFNetworkReachabilityStatusReachableViaWWAN = 1, // 3G 花钱
AFNetworkReachabilityStatusReachableViaWiFi = 2, // 局域网络,不花钱
*/
[[AFNetworkReachabilityManager sharedManager] startMonitoring];
[[AFNetworkReachabilityManager sharedManager] setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
debugLog(@"%ld",(long)status);
}];
根据当前网络状态会输出所对应的状态数值。
下载
//session的默认配置
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//根据配置创建管理者
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *url = [NSURL URLWithString:@"http://smartdsp.xmu.edu.cn/memberpdf/fuxueyang/cvpr2017/cvpr2017.pdf"];
//根据url创建请求对象
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//创建下载任务
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
//设置下载路径
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
//返回文件存放在本地的地址
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
//下载完成后调用方法
debugLog(@"File download to:%@ , %@",filePath,error);
}];
//开始下载任务
[downloadTask resume];
get请求
NSString *urlString = @"https://www.weifar.com/api/ExamQuestion/id";
NSDictionary *parameters = @{@"id":@6};
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
//根据上述参数和请求地址来发送请求
[manager GET:urlString parameters:parameters progress:^(NSProgress * _Nonnull downloadProgress) {
debugLog(@"%@",downloadProgress);
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
//成功获取数据后,进行处理
if (responseObject) {
NSArray *a = responseObject[@"Questions"];
NSDictionary *dic = a[0];
NSString *str = dic[@"BlockDescription"];
debugLog(@"%@",str);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
//请求失败,打印错误
debugLog(@"%@",error);
}];
总结
以上就是AFNetworking
的基本使用,还有其他的一些功能由于没有合适的接口可以进行操作,暂且先搁置下。具体的操作可以参考官方的AFNetworking
API文档,
FMDB的使用方法
最近再看其它大牛写的项目代码,发现许多用到了FMDB
,所以去了解了一下。
FMDB简介
FMDB是一个第三方的开源库,我们可以通过cocopods
搜索并整合到项目里面,FMDB其实就是对SQLite
的API
进行了封装,加上了面向对象的思想,让我们不必使用繁琐的C
语言API
函数,比起直接操作SQLite
更加方便。
并且FMDB
同时兼容 ARC
和非 ARC
工程,会自动根据工程配置来调整相关的内存管理代码。
使用方法
本文使用方法,均参考FMDB
的github
项目文档https://github.com/ccgus/fmdb
引入相关文件
因为是对sqlite
的封装所以我们在项目中需要引入它的库。
之后在文件中导入它的头文件:
#import "FMDB.h"
建立数据库
建立数据库只有简单的一句代码,如果当前路径不存在所需的数据库则会自动创建,若存在则会获取到。当路径为字符(@“”
)时,一个空的数据库将被创建在临时的位置,数据库关闭时候将被自动删除。路径为NULL
时空数据库会被放在内存中,关闭时也将自动被删除。具体信息可以参见:http://www.sqlite.org/inmemorydb.html
#define PATH_OF_DOCUMENT [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]
_path = [PATH_OF_DOCUMENT stringByAppendingPathComponent:@"test.db"];
//创建数据库
FMDatabase *db = [FMDatabase databaseWithPath:_path];
打开数据库
在对数据库进行交互时,必须要先打开它。如果打开失败,可能是权限不足或者资源不足。
if (![db open]) {
// [db release]; // uncomment this line in manual referencing code; in ARC, this is not necessary/permitted
db = nil;
return;
}
执行更新(update)操作
FMDB中除了select
为查询(query
)以为都为更新操作。
例如我们执行一个插入操作的完整步骤为:
static int idx = 1;
FMDatabase *db = [FMDatabase databaseWithPath:_path];
if ([db open]) {
NSString * sql = @"insert into User (name, password) values(?, ?) ";
NSString *name = [NSString stringWithFormat:@"lzh%d",idx++];
BOOL result = [db executeUpdate:sql,name,@"op"];
if (!result) {
debugLog(@"error to insert data");
}else{
debugLog(@"succ to insert data");
}
[db close];
}
查询操作:
FMDatabase *db = [FMDatabase databaseWithPath:_path];
if ([db open]) {
NSString *sql =@"select * from User";
FMResultSet *result = [db executeQuery:sql];
while ([result next]) {
int userId = [result intForColumn:@"id"];
NSString *name = [result stringForColumn:@"name"];
NSString *pass = [result stringForColumn:@"password"];
debugLog(@"user id = %d, name = %@, pass = %@", userId, name, pass);
}
[db close];
}
删除操作:
static int idx = 1;
FMDatabase *db =[FMDatabase databaseWithPath:_path];
if ([db open]) {
NSString *sql = @"delete from User where id = ?";
BOOL result = [db executeUpdate:sql , @(idx++)];
if (!result) {
debugLog(@"error to delete db data");
} else {
debugLog(@"succ to deleta db data");
}
[db close];
}
我们可以看到执行sql
语句的时候用的都是executeUpdate:
方法。
执行查询操作
查询操作与上面的有点区别,我们需要用FMResultSet
来存储我们的查询结果,并调用它的next:
方法来对数据进行逐行操作:
FMDatabase *db = [FMDatabase databaseWithPath:_path];
if ([db open]) {
NSString *sql =@"select * from User";
FMResultSet *result = [db executeQuery:sql];
while ([result next]) {
int userId = [result intForColumn:@"id"];
NSString *name = [result stringForColumn:@"name"];
NSString *pass = [result stringForColumn:@"password"];
debugLog(@"user id = %d, name = %@, pass = %@", userId, name, pass);
}
[db close];
}
上面代码可以发现执行sql
语句变为executeQuery:
方法,该方法会将结果返回为FMResultSet
类型,之后我们需要调用stringForColumn:
对结果进行解析。
FMDB
提供如下多个方法来获取不同类型的数据:
intForColumn:
longForColumn:
longLongIntForColumn:
boolForColumn:
doubleForColumn:
stringForColumn:
dateForColumn:
dataForColumn:
dataNoCopyForColumn:
UTF8StringForColumn:
objectForColumn:
也可以按照列的索引对数据进行获取,{type}ForColumnIndex:
数据参数
我们可以在sql
语句中,用?
表示执行语句的参数,然后在 executeUpdate:
方法来将?
所指代的具体参数传入,例如上面的代码:
NSString * sql = @"insert into User (name, password) values(?, ?) ";
NSString *name = [NSString stringWithFormat:@"lzh%d",idx++];
BOOL result = [db executeUpdate:sql,name,@"op"];
线程安全
FMDatabase
这个类是线程不安全的,如果在多个线程同时使用一个FMDatabase
实例,会造成数据混乱问题。所以,提供了一个FMDatabaseQueue
并且使用它来对多个线程间进行交互,FMDatabaseQueue
对象将通过接入多个线程进行同步和整合。
使用的方法也很简单:
首先创建一个数据库path
来初始化FMDatabaseQueue
,然后就可以将一个闭包 (block) 传入 inDatabase
方法中。
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];
[queue inDatabase:^(FMDatabase *db) {
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];
[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];
FMResultSet *rs = [db executeQuery:@"select * from foo"];
while ([rs next]) {
…
}
}];
按照上面的方法我们可以创建多个线程来异步的对数据库进行操作:
FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:_path];
dispatch_queue_t q1 = dispatch_queue_create("queue1", NULL);
dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL);
dispatch_async(q1, ^{
for (int i =1; i<100; ++i) {
[queue inDatabase:^(FMDatabase *db){
NSString *sql = @"insert into User (name, password) values(?, ?)";
NSString *name = [NSString stringWithFormat:@"queue1 %d", i];
BOOL result = [db executeUpdate:sql,name,@"opop"];
if (!result) {
debugLog(@"error to add db data: %@", name);
} else {
debugLog(@"succ to add db data: %@", name);
}
}];
}
});
dispatch_async(q2,^{
for (int i = 0; i < 100; ++i) {
[queue inDatabase:^(FMDatabase *db) {
NSString * sql = @"insert into user (name, password) values(?, ?) ";
NSString * name = [NSString stringWithFormat:@"queue2 %d", i];
BOOL result = [db executeUpdate:sql, name, @"opop22"];
if (!result) {
debugLog(@"error to add db data: %@", name);
} else {
debugLog(@"succ to add db data: %@", name);
}
}];
}
});
执行后可以发现数据库中的部分表数据如下:
两个线程可以异步执行互不干扰。
上面数据库的显示 使用的是Navicat
,也有其它的数据库管理软件可以显示。
总结
FMDB
是一个在iOS
上简化sqlite API
的第三方库,对sqlite
进行了很有好的封装,便于维护与增加效率。
动态规划
动态规划与分治法很类似,都是通过组合子问题的解来求解原问题。但是不同的是动态规划应用于子问题重叠的情况,即不同的子问题也具有公共的子子问题。分治法在这种情况下,会反复的求解那些公共子子问题。而动态规划算法对每个子子问题只求解一遍,将其保存在一个表格中,避免每次都计算。
钢条切割问题
我们第一个动态规划问题是钢条切割问题。
分治法
我们来先看一下简答的分治法:
//
// main.m
// CUT-ROD
#import <Foundation/Foundation.h>
@interface CUT_ROD:NSObject;
-(NSInteger)CUT_ROD:(NSArray*)P length:(NSInteger)n;
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSArray *c = @[@1,@5,@8,@9,@10,@17,@17,@20,@24,@30];
CUT_ROD *a = [CUT_ROD new];
NSInteger result = [a CUT_ROD:c length:10];
NSLog(@"result is %ld",result);
}
return 0;
}
@implementation CUT_ROD
//简单的分治法,会重复计算子子结果
-(NSInteger)CUT_ROD:(NSArray *)P length:(NSInteger)n{
if (n==0) {
return 0;
}
NSInteger q = -1;
for (NSInteger i=0; i<n; i++) {
q = q>([P[i] integerValue]+[self CUT_ROD:P length:n-i-1]) ? q:([P[i] integerValue]+[self CUT_ROD:P length:n-i-1]);
}
return q;
}
@end
上述代码使用递归来实现的,但是每次都要递归的重复来计算相同的子子问题,如图所示:
所以我们就在想,只要把求解得到的子子问题答案记录下,等到下次要用的时候直接调用它,就可以省下大量的时间。所以我们下面采用动态规划来写一遍。
动态规划
动态规划是一个典型的时空权衡的例子,付出额外的内存空间来降低计算时间。
第一种方法:带备忘的自顶向下算法
//动态规划 带备忘的自顶向下
-(NSInteger)MEMOIZED_CUT_ROD:(NSArray *)P length:(NSInteger)n{
NSMutableArray *logArr =[[NSMutableArray alloc] initWithCapacity:11];
for (int i = 0; i<=10; i++) {
[logArr addObject:@(-1)];
}
return [self MEMOIZED_CUT_ROD_AUX:P length:n log:logArr];
}
-(NSInteger)MEMOIZED_CUT_ROD_AUX:(NSArray*)p length:(NSInteger)n log:(NSMutableArray*)r{
NSInteger q;
if ([r[n] integerValue]>=0) {
return [r[n] integerValue];
}
if (n==0) {
q = 0;
}else{
q = -1;
for (NSInteger i = 0; i<n; i++) {
q = q>[p[i] integerValue] + [self MEMOIZED_CUT_ROD_AUX:p length:n-i-1 log:r] ? q : [p[i] integerValue] + [self MEMOIZED_CUT_ROD_AUX:p length:n-i-1 log:r];
}
}
[r replaceObjectAtIndex:n withObject:@(q)];
return q;
}
MEMOIZED_CUT_ROD
方法引入r
数组,记录每个长度的最优收益值,下面的方法将记录的值存入r
数组中,并调用存入r
的子子问题所得到收益值。
第二个方法,字底向上版本,这个版本更为简单:
-(NSInteger)BOTTOM_UP_CUT_ROD:(NSArray *)P length:(NSInteger)n{
NSMutableArray *arrLog = [[NSMutableArray alloc] initWithCapacity:11];
for (int i = 0; i<=10; i++) {
[arrLog addObject:@(0)];
}
NSInteger q = -1;
for (int j=0; j<n; j++) {
q = -1;
for (int i=0; i<=j; i++) {
NSLog(@"%li",q);
q = q > ([P[i] integerValue] + [arrLog[j-i] integerValue]) ? q : ([P[i] integerValue] + [arrLog[j-i] integerValue]);
NSLog(@"%li",q);
}
[arrLog replaceObjectAtIndex:j+1 withObject:@(q)];
}
return [arrLog[n] integerValue];
}
依次来求解长度从1到n的最大收益。
总结
当我们思考一个动态规划的问题时,最好弄清涉及的子问题与他们的依赖关系。如上图的依赖图为:
Copyright © 2017 Powered by LZH, Theme used GitHub CSS.