怎么处理nsurlsess.run的作用tion的强引用代理

NSURLSession代理是强引用,需要怎么处理?
在NSURLSession的说明文档中,苹果明确指出了代理需要用到强引用.
但是代理使用强引用,苹果自己会不知道这样会造成循环引用吗?&
答案是苹果肯定是知道的,至于要怎么解决问题呢?
AFNetworking的设计者给了我们很好的解决方案,那就是使用单列,单列只会被创建一次,也就保证了内存中有且仅有一个,从而达到了不会被创建多次的情况,完美解决了这个问题.
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。NSURLSession的强引用问题
使用NSURLSession要注意,
他对代理是强引用
#pragma mark - NSURLSessionDownloadDelegate
1.下载完成后被调用的方法(iOS7和iOS8都必须实现)
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
NSLog(@"下载完成");
[self.session invalidateAndCancel];
self.session =
self.downloadTask =
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!NSURLSession笔记(一) 文件下载、断点下载 - 简书
NSURLSession笔记(一) 文件下载、断点下载
qNSURLSession系列笔记:
使用NSURLSession下载文件
配合之前写的NSURLConnection下载文件笔记,有所体会。如果服务器返回的是一些比较大的数据,NSUrlSession 的下载做的是最好的,不需要去考虑什么边下载边写入沙盒的问题,这些都封装好了。
DownloadTask支持BackgroundSession,而dataTask不支持
DownloadTask支持断点续传(下载到一半的时候暂停,重启后继续下载,前提下载的服务器支持断点续传)
使用block回调
- (void)test{
NSURL *url = [NSURL URLWithString:@"xxxxx"];
NSURLSession *session = [NSURLSession sharedSession];
//NSURLResponse响应头,真实类型是NSHTTPURLResponse
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@",location);
[task resume];
在块代码回调的方式,回调的执行线程是异步的(block在子线程中调用,如果拿到数据后要做一些UI更新操作,就要回到主线程刷新)。
回调中location输出的是一个文件路径,通过打断点,可以看到要下载的文件在被下载时存在于该路径下,但代码块执行完毕后就被删除了。原因:
这里block的location参数在api中的描述如下:The location of a temporary file where the server’s response is stored. You must move this file or open it for reading before your completion handler returns. Otherwise, the file is deleted, and the data is lost.
下载文件会保存在沙盒的tmp文件下,如果在回调方法中,不做任何处理,下载的文件会被删除。这样设计的目的:通常从网络上下载文件,zip格式文件最多,这样可以替用户节约流量;如果是zip包,下载之后,需要解压缩,解压之后原始的zip就不需要了,系统会自动帮我们删除初始zip文件。
因此需要作出如下修改:
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
NSLog(@"%@",location);//tmp路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
// response.suggestedFilename : 建议的文件名
NSString *file = [caches stringByAppendingPathComponent:response.suggestedFilename];
// 将临时文件move或者copy 到Caches文件夹
// AtPath : 剪切前的文件路径
ToPath : 剪切后的文件路径
[[NSFileManager defaultManager] moveItemAtPath:location.path toPath:file error:nil];
沙盒目录:
Documents:应用中用户数据可以放在这里,iTunes备份和恢复的时候会包括此目录。[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject]
tmp:存放临时文件,iTunes不会备份和恢复此目录,此目录下文件可能会在应用退出后删除
Library/Caches:存放缓存文件,iTunes不会备份此目录,此目录下文件不会在应用退出删除。NSString *cacheStr = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
下载进度跟进:使用代理NSURLSessionDownloadDelegate
除了NSURLSessionDelegate用来处理Session层次的事件,NSURLSessionTaskDelegate处理Task的共性事件之外,还有NSURLSessionDownloadTaskDelegate 用来特别处理Download事件
要使用代理就不能使用回调代码块
如果要跟进下载进度(也就是使用代理),不能使用全局session:sharesession
NSURLSessionConfiguration 提供了一个全局的网络环境配置,包括:身份验证,浏览器类型,cookie,缓存,超时时长。一旦设置可以全局共享,替代NSURLRequset中的附加信息!
下面的代码中,下载的文件在下载时存在于沙盒tmp文件夹下
没有内存峰值问题
//全局网络会话,管理所有网络任务
@property (nonatomic , strong) NSURLSession *
//下载任务
@property (nonatomic , strong) NSURLSessionDownloadTask *downloadT
- (NSURLSession *)session{
if (_session == nil) {
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
- (void)start{
NSURL *url = [NSURL URLWithString:@"xxxxx"];
//要使用代理就不能使用回调代码块
//如果在块代码回调的方式,回调的执行线程是异步的。
self.downloadTask = [self.session downloadTaskWithURL:url];
[self.downloadTask resume];
//在iOS7中三个代理方法都是必须的,到了8.0只有第一个是必须的
//要支持iOS7&8,三个方法都要实现
//下载完成方法,一定要在这个函数返回之前,对数据进行使用,或者保存
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSLog(@"finish %@",location);
//生成沙盒的路径,对数据进行保存
NSArray *docs = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [docs[0] stringByAppendingPathComponent:downloadTask.response.suggestedFilename];
NSURL *toURL = [NSURL fileURLWithPath:path];
[[NSFileManager defaultManager] copyItemAtURL:location toURL:toURL error:nil];
//下载进度
bytesWritten
本次下载的字节数
totalBytesWritten
已经下载的字节数
totalBytesExpectedToWrite
期望下载的字节数:文件总大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
float progress = (float)totalBytesWritten/totalBytesExpectedToW
NSLog(@"%f",progress);
//下载续传数据
//resume之后会调用这个方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{
//不管什么类型的task结束,URLSession:task:didCompleteWithError:都会被调用,根据error是否为空判断成功失败
//用户取消下载,调用cancelByProducingResumeData:也会调用这个代理方法
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error{
self.resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
代理的方式能监听下载进度,不会将数据写入缓存,所以适合大文件,而block的方式将数据写入缓存,不适合大文件下载
NSURLConnection需要手动设置请求头的Range的方式实现,NSURLSession的resumeData已经包含了,也就是NSURLSession已经实现了。
- (IBAction)start{
NSURL *url = [NSURL URLWithString:@"xxxxx"];
self.downloadTask = [self.session downloadTaskWithURL:url];
[self.downloadTask resume];
2.暂停:NSURLSessionDownloadTask的- cancelByProducingResumeData:(void (^)(NSData * __nullable resumeData))completionHandler
回调block里参数resumeData包含了继续下载文件的位置信息,下次继续下载的时候是从这个位置开始。
- (IBAction)pause{
//取消下载任务
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
//参数resumeData:续传的数据(已经下载下来的数据)
NSLog(@"数据长度 %tu", resumeData.length);
//释放下载任务
//self.downloadTask =
如果任务已经被暂停(点击了一次暂停键),不应该能够再次被暂停(再点一次暂停按钮)。上面这样写,当第二次点暂停键的时候会打印出:“数据长度 0”
因此在暂停之后要释放下载任务:self.downloadTask =
由于在第3步“继续下载”(见下)中需要使用到续传数据,因此需要把续传数据保存起来。
@property (nonatomic , strong) NSData *resumeD
- (IBAction)pause{
[self.downloadTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
//resumeData:续传的数据
NSLog(@"数据长度 %tu", resumeData.length);
self.resumeData = resumeD
//释放下载任务//如果任务已经被暂停,不应该能够再次被暂停(连点两次暂停按钮)
self.downloadTask =
这里是否涉及block循环引用的问题?是的,有循环引用问题。self对task进行了强引用,task又对block进行了引用,block又对self进行引用,这就形成了循环使用。
解决方法:对self进行弱引用__weak typeof(self) ws =
cancelByProducingResumeData:取消任务是不能恢复的,只能重新创建任务。
- (IBAction)resume{
//使用“续传数据”启动下载任务,使用的是之前保存的续传数据
//creat a new task
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
[self.downloadTask resume];
使用之前保存的续传数据来启动下载任务,这里的downloadTask是新创建的,和之前那个不是同一个。另外因为所有的任务task默认都是挂起不执行的,所以最后要resume一下。
运行程序,点击 开始-&暂停-&继续(执行到这里可以正常续传)-&继续(这是任务会回到从“续传数据”的地方开始下载,放个进度条控件就可以看见了。。。)
续传数据的作用就是建立新的下载任务,一旦下载任务建立以后,续传数据就没有用了。因此重新建立下载任务之后要清空续传数据self.resumeData = nil
- (IBAction)resume{
if (self.resumeData == nil) {
NSLog(@"没有暂停的任务");
//使用“续传数据”启动下载任务,使用的是之前保存的续传数据
//续传数据的作用就是建立新的下载任务,一旦下载任务建立以后,续传数据就没有用了
self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
//清空续传数据
self.resumeData =
[self.downloadTask resume];
源自网络:下载交互过程顺序图
这种断点下载只支持应用内断点,如果程序在下载过程中途关闭,则不能恢复下载
下载失败后如何恢复下载?
不管什么类型的task结束,URLSession:task:didCompleteWithError:都会被调用,根据error是否为空判断成功失败。在任务失败的情况下,大多数app应当尝试重新请求直到用户取消任务或者服务端返回error code于是这个任务不会成功。
NSError对象的userInfo字典包含一个Key值为NSURLSessionDownloadTaskResumeData的value,应将这个值传给downloadTaskWithResumeData:或者downloadTaskWithResumeData: completionHandler:并创建一个新的下载任务继续执行之前的下载。
- (void)URLSession:(NSURLSession *)sessiona
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
if (error) {
if ([error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]) {
//self.resumeData = [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData];//做到这步
//重新请求
NSURLSessionTask *task = [[self backgroundURLSession] downloadTaskWithResumeData: [error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData]];
[task resume];
一旦任务失败就马上重新请求,不过调用cancelByProducingResumeData:方法会触发URLSession: task:didCompleteWithError:(error有值),所以就做到把resumeData保存下来。
NSURLSession发起任务并且对任务强引用
所有的任务都是由session发起的,任务一旦发起,session就会对任务进行强引用。一旦任务被取消,session就不再对任务进行强引用,arc中如果没有对象对某一个对象强引用,就会被立即释放。因此任务(task)就会被立即释放
如果是@property (nonatomic , strong) NSURLSessionDownloadTask *downloadT,在“暂停”中self.downloadTask =这句也可以不写。
NSURLSession 的代理工作队列
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSURLSession 在异步处理上要比NSURLConnection要好。
下载本身是异步的,是NSURLSession统一调度的。(在界面上放置一个uitextview,当下载任务开始的时候拖拽textview,下载任务并不会受到影响)(NSURLConnection在初始化时确定发送的是同步还是异步请求,而NSURLSession智能异步发送网络请求)
代理方法的工作队列指的是:当网络事件需要监听的时候,去执行代理方法所调度的队列
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];参数delegateQueue:指定调度代理方法执行的队列,并不会影响到session本身的异步执行
nil :代理在异步多个线程执行
[[NSOperationQueue alloc]init]和nil的执行效果一样,如果希望代理在异步执行,直接使用nil即可
[NSOperationQueue mainQueue]:主队列
如果使用block回调的方式,回调的执行线程是异步的。
NSURLSession:session对象会对代理强引用
The session object keeps a strong reference to the delegate until your app exits or explicitly invalidates the session. If you do not invalidate the session by calling the invalidateAndCancel or finishTasksAndInvalidate method, your app leaks memory until it exits.
session会对代理进行强引用,如果任务执行结束后不取消session,会造成内存泄漏。
使用代理,一般委托方对代理方弱引用。一旦委托方对代理方强引用,则会产生循环引用:
_session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
这里session对象是委托方,viewController是session的代理,session对vc强引用。而通常navgationVC导航控制器也会对VC进行强引用。在这种情况下nav对vc pop,vc并不会被释放掉(点击开始下载文件,无论文件有没有下载完,点击导航栏返回按钮vc都无法跳进dealloc)(session也不会被取消,下载中的任务仍然继续)
- (void)dealloc{
NSLog(@"销毁了");
取消会话对象的位置:
1.下载完成时
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSLog(@"finish %@",location);
//完成任务,如果会话已经被设置成完成,就无法再次使用session(就是说点开始下载,完成之后再点一次开始,此时无法下载)
[self.session finishTasksAndInvalidate];//点击导航栏返回按钮可以跳进dealloc,打印出“销毁了”
//解决办法,清空session(这样就可以懒加载了)
self.session =
2.视图控制器销毁前
- (void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
//取消会话
[self.session invalidateAndCancel];
self.session =
当不再需要连接时,可以调用Session的invalidateAndCancel直接关闭,或者调用finishTasksAndInvalidate等待当前Task结束后关闭。这时Delegate会收到URLSession:didBecomeInvalidWithError:这个事件。Delegate收到这个事件之后会被解引用。
两种方式对比:
方法1:可以保证文件”可能“完整被下载完,但这种方法会重复创建和销毁session,会造成额外的开销
方法2:只是在离开界面前销毁sission,相对开销会小。缺点:如果一个文件没有下载完成会直接被取消掉
真正的解决方法:
在网络访问中,应该将所有的网络访问操作,封装到一个方法中。由一个统一的单例来负责处理所有的网络事件。session对代理进行强引用,而单例本身就是一个静态实例,本身就不需要被释放。
正在下载时关掉强制退出程序再重启的断点续传
得益于这些文章,从它们那学到了很多:
第一种方法
基本上和之前讲的差不多,但是用到NSURLSession后台模式。
利用在NSURLSessionConfiguration设置的identifier。
在应用被杀掉前,iOS系统保存应用下载session的信息。重新启动应用,当identifier相同的时候(苹果通过identifier找到对应的session数据),一旦生成Session对象并设置Delegate(否则会因为没有对 session 的 delegate 进行设定,相应的delegate方法不会被调用),iOS系统会对之前下载中的任务进行依次回调URLSession:task:didCompleteWithError:方法。
但是当ID不相同,这些情况就收不到了。因此为了不让自己的消息被别的应用程序收到,或者收到别的应用程序的消息,起见ID还是和程序的Bundle名称绑定上比较好,至少保证唯一性。
还没有下载完的时候关掉强制退出程序再重启,点击继续按钮进行续传。
ps:如果用户先暂停下载、退出程序,再重启,那么利用在NSURLSessionConfiguration设置ID这种方法进行续传就不可行了。下面第二种方法就没有这个问题了。
第二种方法
在后台下载模式下,
当使用NSURLSessionDownloadTask进行下载的时候,系统会在cache文件夹下创建一个下载的路径(/Downloads),路径下会有一个以"CFNetworking"打头的.tmp文件,这个就是我们正在下载中的文件。而当我们调用了cancelByProducingResumeData:方法后,会得到resumeData。而原本存在于Downloads文件下的.tmp文件,则被移动到了tmp文件夹目录下。当我们再次进行resume操作的时候,下载文件则又被移回到了Downloads文件夹下。
先来看看resumeData到底是什么东西:通过断点,resumeData转换为string,发现是一个XML文件,里面包含了关于.tmp文件的一些关键点的描述,包括"Range","key","download url",tmp文件的名字等等信息。
暂停时得到的resumeData与.tmp文件是一一对应的。DownloadTask进行断点续传的时候,会根据resumeData中的temp文件名去寻找.tmp文件,然后校验后再根据"Range"属性去进行断点续传。
因此,程序被杀死的断点下载具体实现思路:
0.选择document文件夹作为安全目录。
1.暂停下载时先清掉document文件夹中的.tmp文件;然后把tmp文件夹中的.tmp文件复制到document文件夹。并且把resumeData另外以文件的形式保存下来。
2.resumeDownload。先清掉tmp文件夹下的.tmp文件;然后把document中的.tmp文件复制到tmp文件夹。然后利用保存下来的resumeData对downloadTask resume。
3.(关键)设置一个Bool变量用来判断是否正在下载中,同时用一个周期事件每隔一段时间暂停一次。保存进度步骤同1。
- (void)download{
//如果设置保存间隔过长,中间杀掉进程可能会损失较多进度
_timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(pauseToStoreData) userInfo:nil repeats:YES];
NSString *downloadURLString = @"http://sw.bos.baidu.com/sw-search-sp/software/797b/QQ_mac_5.0.2.dmg";
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:downloadURLString]];
self.resumeData = [NSData dataWithContentsOfFile:self.resumeDataPath];
if (self.resumeData) {
NSArray *paths = [self.fileManager subpathsAtPath:self.docPath];//查找给定路径下的所有子路径.深度查找,不限于当前层
for (NSString *filePath in paths){
if ([filePath rangeOfString:@"CFNetworkDownload"].length&0)
//1.先清掉tmp文件夹下的tmp文件 -removeItemAtPath:目标目录是文件
[self.fileManager removeItemAtPath:[self.tmpPath stringByAppendingPathComponent:filePath] error:nil];
//2.把doucment中的tmp文件复制到tmp文件夹
self.docTmpFilePath = [_docPath stringByAppendingPathComponent:filePath];//document文件夹中tmp文件的路径
//-copyItemAtPath:toPath:error:拷贝到目标目录的时候,如果文件已经存在则会直接失败;目标目录必须是文件(一定要以文件名结尾,而不要以文件夹结尾)
[self.fileManager copyItemAtPath:_docTmpFilePath toPath:[self.tmpPath stringByAppendingPathComponent:filePath] error:nil];
self.task = [self.backgroundSession downloadTaskWithResumeData:self.resumeData];
self.resumeData =
self.task = [self.backgroundSession downloadTaskWithRequest:request];
[self.task resume];
- (void)pauseDownload{
__weak typeof(self) ws =
[self.task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
ws.resumeData = resumeD
[resumeData writeToFile:self.resumeDataPath atomically:YES];
NSArray *paths = [self.fileManager subpathsAtPath:self.tmpPath];
for (NSString *filePath in paths)
if ([filePath rangeOfString:@"CFNetworkDownload"].length&0)
//1.先清掉document文件夹中的tmp文件
[self.fileManager removeItemAtPath:[self.docPath stringByAppendingPathComponent:filePath] error:nil];
//2.把tmp文件夹中的tmp文件复制到document文件夹
self.docTmpFilePath = [self.docPath stringByAppendingPathComponent:filePath];
NSString *path = [self.tmpPath stringByAppendingPathComponent:filePath];
[self.fileManager copyItemAtPath:path toPath:_docTmpFilePath error:nil];
- (void)pauseToStoreData
if (!_downloading)
[_task cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
self.resumeData = resumeD
self.task =
[resumeData writeToFile:self.resumeDataPath atomically:YES];
NSArray *paths = [self.fileManager subpathsAtPath:self.tmpPath];
for (NSString *filePath in paths)
if ([filePath rangeOfString:@"CFNetworkDownload"].length&0)
//1.先清掉document文件夹中的tmp文件
[self.fileManager removeItemAtPath:[self.docPath stringByAppendingPathComponent:filePath] error:nil];
//2.把tmp文件夹中的tmp文件复制到document文件夹
self.docTmpFilePath = [self.docPath stringByAppendingPathComponent:filePath];
NSString *path = [self.tmpPath stringByAppendingPathComponent:filePath];
[self.fileManager copyItemAtPath:path toPath:_docTmpFilePath error:nil];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (self.resumeData)
self.task = [self.backgroundSession downloadTaskWithResumeData:self.resumeData];
[self.task resume];
因为每隔一段时间暂停一次保存进度,在实际运行中发现此处会有明显的停顿感。设置的周期间隔过长过短都不好,过短会影响效率,过长则有可能在突然杀掉进程时来不及保存进度导致进度丢失过多。
留坑待填:
1.防止重复下载。“当下载的长度等于服务器响应的长度时说明下载过了。”
博客搬迁到github https://github.com/huixinHu
简书偶尔上上更新
尊重知识,转发请注明出处:基于iOS 10、realm封装的下载器(支持存储读取、断点续传、后台下载、杀死APP重启后的断点续传等功能) 概要在决定自己封装一个下载器前,我本以为没有那么复杂,可在实际开发过程中困难重重,再加上iOS10和Xcode8的发布,更是带来一些意外...
NSURLSession 类及其相关类为下载内容提供了接口。这个 API 提供了一系列丰富的代理方法来支持授权,而且让你的 APP 在后台被挂起时也能继续下载。 通过代理服务器的和 SOCKS 网关为用户配置好系统设置,NSURLSession 类完全支持 data, fi...
Github : Jerry4me, Demo : JRBgSessionDemo &a&前言&/a& 本文主要是结合官方文档, 挖掘NSURLSession的类层次结构及其联系, 总结出关于NSURLSession的一些关键点及其用法. 关于NSURLSession为什么...
一.概述 NSURLSession始于ios7.它具有访问接口,上传/下载数据,断点继传和后台下载等功能:其使用步骤: 1.创建session指定其configuration 2.由session执行任务得到task 3. task调用resume,启动网络请求 1.tas...
NSURLSession 使用步骤使用NSURLSession对象创建Task,然后执行Task -(void)get{//1.确定URLNSURL*url = [NSURLURLWithString:@&http://120.25.226.186:32812/login?...
引子 本文使用Nodejs主要实现了如下形式的命令行程序 文中option的取值通过options.option名的方式取得,option名在option定义时,通过--option名定义 导入第三方package co以同步的书写方式书写回调函数 commander解析命...
一、今日早餐 紫薯饼,酸奶,苹果 紫薯饼制作方法很简单:紫薯300g、糯米粉100g、全麦粉50g加入适量牛奶揉成光滑面团,然后分成5一个个50g的剂子,再用月饼模具取造型,上锅蒸20分钟左右即可。 面团看起来很粉嫩,没想到蒸熟后颜色变得很深,看来如果想要浅一点的颜色,必须...
写这个题目并不是想说,我日常的生活非常的忙碌无为或者生活没有目标。 反思走出校园的十年间,我努力工作,认真生活。奋斗的目的更多是因为自己,自己的前途也好,改变自己的生活境遇也罢,总之是为自己一个人。 再后来,当结婚生完了孩子,又开始为大宝,二宝忙碌。这一切的一切之中,唯独没...
零点冷空气剃光树的头发 弹指间季节的欲望 拉直熨平打包入库爆仓出库封路塞车抵达抵达抵达派送 无人区 欲火将思念焗成铅字影子割断了光线,兀自走远 人生就是一场不停的客串,打工如是,恋爱如是旭主笔,深入情感与心理,浅出世间众生相,认真客串
昨夜仰观天象,见紫微星东移,掐指一算,中国女排里约之行异常凶险,如果能躲过三灾八难,冠军将成囊中之物。 据说湖南郴州与女排有旷世不解之谜,慢慢看,链景君会给你指引... 其实所谓的星象学都是忽悠,链景君真正精通的是大数据分析。用科学的方法得出结论,然后隐去其严谨的推理过程,...}

我要回帖

更多关于 sesstion 用户管理 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信