iOS中实现多线程的技术方案

pthread 实现多线程操作

代码实现:

void * run(void *param)
{
   for (NSInteger i = 0; i < 1000; i++) {
       NSLog(@"---buttonclick---%zd---%@", i, [NSThread currentThread]);
   }    return NULL;
} @implementation ViewController - (IBAction)clickButton:(id)sender {
   // 定义一个线程
   pthread_t thread;    // 创建一个线程  (参1)pthread_t *restrict:创建线程的指针,(参2)const pthread_attr_t *restrict:线程属性  (参3)void *(*)(void *):线程执行的函数的指针,(参4)void *restrict:null
   pthread_create(&thread, NULL, run, NULL);    // 何时回收线程不需要你考虑
   pthread_t thread2;    pthread_create(&thread2, NULL, run, NULL); }

NSThread实现多线程

一个 NSThread 对象就代表一条线程

创建线程的多种方式

  • 第一种方式:先创建再启动线程

      // 创建线程
     NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];  // 线程启动了,事情做完了才会死, 一个NSThread对象就代表一条线程
     [thread start];
  • 第二种:直接创建并启动线程

      // 直接创建并启动线程
     [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"jack"];
  • 第三种:

      // 直接创建并启动线程
     [self performSelectorInBackground:@selector(run:) withObject:@"jack"];  // 使线程进入阻塞状态
     [NSThread sleepForTimeInterval:2.0];  #pragma mark - 执行run方法
     - (void)run:(NSString *)param
     {
         // 当前线程是否是主线程
         for (NSInteger i = 0; i < 100; i++) {
             NSLog(@"---%@---%zd---%d", [NSThread currentThread], i,  [NSThread isMainThread]);
         }
     }
  • 方法2和方法3的优点:快捷 方法1的优点:可以轻松拿到线程

线程间通信

  • 线程间通信的体现

1个线程传递数据给另1个线程

在1个线程中执行完特定任务后,转到另1个线程继续执行任务

线程间通信的常用方法:小程序图片下载

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   // 获取图片的url
   NSURL *url = [NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"];
// 另开1条线程 object用于数据的传递
   NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downLoadWithURL:) object:url];
   // 由于下面下载图片的耗时太长,应领开启线程来完成
   [thread start];
} // 下载图片
- (void)downLoadWithURL:(NSURL *)url
{
   NSLog(@"%@", [NSThread currentThread]);
   // 下载图片
   NSData *data = [NSData dataWithContentsOfURL:url];
   // 生成图片
   UIImage *image = [UIImage imageWithData:data];    // 返回主线程显示图片
   [self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}

以上两种方式使用线程已经过时了,开发中我们操作线程大多都使用 GCD 和 NSOperation 来实现多线程操作。

下面我就给大家系统的介绍一下 GCD 是如何实现多线程的

GCD 实现多线程

GCD 简介

GCD 全称是Grand Central Dispatch,可译为“超级厉害的中枢调度器”,GCD 是苹果公司为多核的并行运算提出的解决方案, GCD会自动利用更多的 CPU 内核(比如双核、四核)来开启线程执行任务,GCD 会自动管理线程的生命周期(创建线程、调度任务、销毁线程),不需要我们程序员手动管理内存。

任务和队列

任务:在同步函数和异步函数中执行

队列:用来存放任务(并发 串行)

GCD会自动将队列中的任务取出,放到对应的线程,任务的取出遵循FIFO,即先入先出队列,First Input First Output 的缩写。先进入的任务先完成并结束,再执行后面的任务。

同步函数和异步函数,并发队列和串行队列

  • 用同步的方式执行任务:在当前线程中可立即执行任务,不具备开启线程的能力

  • 用异步的方式执行任务:在当前线程结束时执行任务,具备开启新的线程的能力

  • 并发队列:允许多个任务同时执行

  • 串行队列:一个任务执行完毕后,再执行下一个任务

创建并发/串行队列代码:

// 创建并发队列
// 参1:const char *label 队列名称
// 参2:dispatch_queue_attr_t attr 队列类型
dispatch_queue_t queueConcurrent = dispatch_queue_create("520it.com", DISPATCH_QUEUE_CONCURRENT); // 创建串行队列  serial 串行  concurrent并发
dispatch_queue_t queueSerial = dispatch_queue_create("520it.com", DISPATCH_QUEUE_SERIAL); // 获取全局队列 全局队列是并发队列
// 参1:队列的优先级
// 参2:0(以后可能用到的参数)
dispatch_queue_t queueGlobal = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 全局并发队列的优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台 // 获取主队列  在主队列中的任务都会在主线程中执行。
dispatch_queue_t queueMain = dispatch_get_main_queue();

同步/异步函数代码表示:

// GCD同步函数串行队列(立即执行,当前线程)
// 参1: dispatch_queue_t queue 队列
// 参2: 任务
dispatch_sync(queueSerial, ^{
   for (NSInteger i = 0; i < 10; i++) {
       NSLog(@"~~~%@", [NSThread currentThread]);
  }
}); // 同步函数并行队列(立即执行,当前线程)
dispatch_sync(queueConcurrent, ^{
   for (NSInteger i = 0; i < 10; i++) {
       NSLog(@"~~~%@", [NSThread currentThread]);
   }
}); // 异步函数串行队列 (另开线程,多个任务按顺序执行)
dispatch_async(queueSerial, ^{
   dispatch_async(queueSerial, ^{
       for (NSInteger i = 0; i < 10; i++) {
           NSLog(@"~~~%@", [NSThread currentThread]);
       }
   });
   dispatch_async(queueSerial, ^{
       for (NSInteger i = 0; i < 10; i++) {
           NSLog(@"~~~%@", [NSThread currentThread]);
       }
   });
   dispatch_async(queueSerial, ^{
       for (NSInteger i = 0; i < 10; i++) {
           NSLog(@"~~~%@", [NSThread currentThread]);
       }
   });
}); // 异步函数并行队列 (另开线程,多个任务一起执行)
dispatch_async(queueConcurrent, ^{
   dispatch_async(queueSerial, ^{
           for (NSInteger i = 0; i < 10; i++) {
               NSLog(@"~~~%@", [NSThread currentThread]);
           }
   });
   dispatch_async(queueSerial, ^{
       for (NSInteger i = 0; i < 10; i++) {
           NSLog(@"~~~%@", [NSThread currentThread]);
       }
   });
   dispatch_async(queueSerial, ^{
       for (NSInteger i = 0; i < 10; i++) {
           NSLog(@"~~~%@", [NSThread currentThread]);
       }
   });
}); // 主队列:(任何一个任务只要在主队列中,都会加入到主线程的队列中执行)

注意:使用sync函数(同步函数)往当前串行队列中添加任务,会卡住当前的串行队列

解释:使用同步函数添加任务 A 到串行队列,说明要在当前串行队列立即执行任务 A ,任务 A 执行完后,才会执行任务 A 后面的代码。但当前队列是串行队列,也就是说任务 A 必须等到当前串行队列中正在执行的任务 B 完成之后才能执行,因此又必须先执行任务 A 中立即执行任务,又要必须等到任务 B 执行完以后才能执行下一个任务,所以就会卡死。你等我,我等你,谁也无法执行。

GCD实现线程通信

小项目:下载图片

代码如下:

// 获取图片的url
NSURL *url = [NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]; // 开启线程下载图片
dispatch_queue_t queue = dispatch_queue_create("111", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
   NSData *data = [NSData dataWithContentsOfURL:url];
   UIImage *image = [UIImage imageWithData:data];    // 下载完成后返回主线程显示图片
   dispatch_async(dispatch_get_main_queue(), ^{
       self.imageView.image = image;
   });
});

GCD其他常用函数

dispatch_barrier 栅栏

// 1.barrier : 在barrier前面的先执行,然后再执行barrier,然后再执行barrier后面的 barrier的queue不能是全局的并发队列
dispatch_queue_t queue = dispatch_queue_create("11", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, ^{
   for (int i = 0;  i < 100; i++) {
       NSLog(@"%@--1", [NSThread currentThread]);
   }
}); dispatch_async(queue, ^{
   for (int i = 0;  i < 100; i++) {
       NSLog(@"%@--2", [NSThread currentThread]);
   }
}); dispatch_barrier_async(queue, ^{
   for (int i = 0;  i < 100; i++) {
       NSLog(@"%@--3", [NSThread currentThread]);
   }
}); dispatch_async(queue, ^{
   for (int i = 0;  i < 100; i++) {
       NSLog(@"%@--4", [NSThread currentThread]);
   }
});

dispatch_after 延迟执行

// 延迟执行
// 方法1
[self performSelector:@selector(run:) withObject:@"参数" afterDelay:2.0]; // 方法2
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
   for (NSInteger i = 0; i < 100; i++) {
       NSLog(@"%@", [NSThread currentThread]);
   }
}); // 方法3
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];

dispatch_once 整个程序运行中执行一次

// 整个程序中只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
   // 一次性代码
});

作用:实现某个类的单粒对象

单例模式:在整个应用程序中,共享一份资源(这份资源只需要创建初始化1次)

static id _person;
+ (instancetype)sharePerson
{
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
       _person = [[super alloc] init];
   });
   return _person;
} + (instancetype)allocWithZone:(struct _NSZone *)zone
{
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
       _person = [super allocWithZone:zone];
   });
   return _person;
} - (id)copy
{
   return _person;
}

开发中一般自定义成宏,比较方便,一行代码搞定。

dispatch_apply 快速迭代

示例小程序:将一个文件夹中的图片剪切到另一个文件夹

// 将图片剪切到另一个文件夹里
NSString *from = @"/Users/Ammar/Pictures/壁纸";
NSString *to = @"/Users/Ammar/Pictures/to";
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *subPaths = [manager subpathsAtPath:from]; // 快速迭代
dispatch_apply(subPaths.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t index) {
  NSLog(@"%@ - %zd", [NSThread currentThread], index);
   NSString *subPath = subPaths[index];
   NSString *fromPath = [from stringByAppendingPathComponent:subPath];
   NSString *toPath = [to stringByAppendingPathComponent:subPath];    // 剪切
   [manager moveItemAtPath:fromPath toPath:toPath error:nil];
   NSLog(@"%@---%zd", [NSThread currentThread], index);
});

dispatch_group 队列组

示例小程序:需求下载图片1 下载图片2 将图片1和图片2合成新的图片

// 创建队列
   dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// 创建组
dispatch_group_t group = dispatch_group_create(); // 用组队列下载图片1
dispatch_group_async(group, queue, ^{
   NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]];
   self.image1 = [UIImage imageWithData:data];
   NSLog(@"1%@", [NSThread currentThread]);
}); // 用组队列下载图片2
dispatch_group_async(group, queue, ^{
   NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]];
   self.image2 = [UIImage imageWithData:data];
   NSLog(@"2%@", [NSThread currentThread]);
}); // 将图片1和图片2合成一张图片
dispatch_group_notify(group, queue, ^{
   CGFloat imageW = self.imageView.bounds.size.width;
   CGFloat imageH = self.imageView.bounds.size.height;    // 开启位图上下文
   UIGraphicsBeginImageContext(self.imageView.bounds.size);    // 画图
   [self.image1 drawInRect:CGRectMake(0, 0, imageW * 0.5, imageH)];
   [self.image2 drawInRect:CGRectMake(imageW * 0.5, 0, imageW * 0.5, imageH)];    // 将图片取出
   UIImage *image = UIGraphicsGetImageFromCurrentImageContext();    // 关闭图形上下文
   UIGraphicsEndImageContext();    // 在主线程上显示图片
   dispatch_async(dispatch_get_main_queue(), ^{
       self.imageView.image = image;
   });
   NSLog(@"3%@", [NSThread currentThread]);
});

GCD定时器

GCD定时器不受Mode影响因此比NSTimer要准确

static int count = 0;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
   // 这句话的意思现在很好懂了
}); // GCD定时器
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 1.创建一个定时器源 // 参1:类型定时器
// 参2:句柄
// 参3:mask传0
// 参4:队列  (注意:dispatch_source_t本质是OC对象,表示源)
self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); // 严谨起见,时间间隔需要用单位int64_t,做乘法以后单位就变了
// 下面这句代码表示回调函数时间间隔是多少
int64_t interval = (int64_t)(2.0 * NSEC_PER_SEC); // 如何设置开始时间 CGD给我们了一个设置时间的方法  
// 参1:dispatch_time_t when 传一个时间, delta是增量 dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); // 从现在起3秒后开始 // 2.设置定时器的各种属性 // 参1:timer
// 参2:开始时间
// 参3:时间间隔
// 参4:传0 不需要   DISPATCH_TIME_NOW 表示现在 GCD 时间用 NS 表示
dispatch_source_set_timer(self.timer, start, interval, 0); // 3.设置回调(即每次间隔要做什么事情)
dispatch_source_set_event_handler(self.timer, ^{
   NSLog(@"----------------%@", [NSThread currentThread]);    // 如果希望做5次就停掉
   count++;
   if (count == 5) {
       dispatch_cancel(self.timer);
       self.timer = nil;
   }
}); // 4.启动定时器  (恢复)
dispatch_resume(self.timer);

讲完 GCD 就该讲讲 NSOperation,它是 GCD 的面向对象的封装,使用起来也更方便,

NSOperation实现多线程

NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类

NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法

使用 NSOperation 实现多线程的步骤:

创建任务 NSOperation 对象
创建 NSOperationQueue 队列
将任务 NSOperation 对象 add 到 NSOperationQueue 队列中去

NSInvocationOperation

代码如下:

NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

[op start];

注意:默认情况下,调用了start方法后并不会开一条新的线程去执行,而是在当前线程同步执行操作,只有将 NSOperation 放到一个 NSOperationQueue 中,才会异步执行操作

NSBlockOperation

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
   // 在主线程
     NSLog(@"下载1------%@", [NSThread currentThread]);
}]; // 添加额外的任务(在子线程执行),封装数大于1才会异步执行
[op addExecutionBlock:^{
   NSLog(@"下载2------%@", [NSThread currentThread]);
}];

自定义Operation:需要实现- (void)main方法,需要做的事情放在mian方法中

NSOperationQueue

使用NSOperationQueue创建队列:主队列和全局队列

// 创建一个其他队列(包括串行队列和并发队列) 放到这个队列中的NSOperation对象会自动放到子线程中执行

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 创建一个主队列,放到这个队列中的NSOperation对象会自动放到子线程中执行
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; // 表示并发数量:即同时执行任务的最大数。
queue.maxConcurrentOperationCount = 1;

队列的取消、暂停、恢复:

// NSOpertion的 - cancel 方法也可以停止单个操作
- (void)cancelAllOperations;
// YES代表暂停队列,NO代表恢复队列
- (void)setSuspended:(BOOL)b;

添加依赖

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
   NSLog(@"download1 -------------- %@", [NSThread currentThread]);
}]; NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
   NSLog(@"download2 -------------- %@", [NSThread currentThread]);
}]; NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
   NSLog(@"download3 -------------- %@", [NSThread currentThread]);
}]; // 添加依赖: block1 和 block2执行完后 再执行 block3  block3依赖于block1和block2 // 给block3添加依赖 让block3在block1和block2之后执行
[block3 addDependency:block1];
[block3 addDependency:block2]; [queue addOperation:block1];
[queue addOperation:block2];
[queue addOperation:block3];

注意:不能循环依赖,但可以跨队列依赖,不管NSOperation对象在哪个队列。只要是两个NSOperation对象就可以依赖

线程间通信

示例:下载图片

// 下载图片 operation实现线程间通信
[[[NSOperationQueue alloc] init] addOperation:[NSBlockOperation blockOperationWithBlock:^{
   UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]]];    // 返回主线程
   [[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{
       self.imageView.image = image;
   }]]; }]];

示例:下载图片1和图片2 并合成图片

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

// 下载图片1
__block UIImage *image1 = nil;
NSBlockOperation *block1 = [NSBlockOperation blockOperationWithBlock:^{
   image1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]]];
}]; // 下载图片2
__block UIImage *image2 = nil;
NSBlockOperation *block2 = [NSBlockOperation blockOperationWithBlock:^{
   image2 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://7xjanq.com1.z0.glb.clouddn.com/6478.jpg"]]]; }]; CGFloat imageW = self.imageView.bounds.size.width;
CGFloat imageH = self.imageView.bounds.size.height; // 合成图片
NSBlockOperation *block3 = [NSBlockOperation blockOperationWithBlock:^{
   UIGraphicsBeginImageContext(CGSizeMake(imageW, imageH));
   [image1 drawInRect:CGRectMake(0, 0, imageW * 0.5, imageH)];
   [image2 drawInRect:CGRectMake(0.5 * imageW, 0, 0.5 * imageW, imageH)];    UIImage *image3 = UIGraphicsGetImageFromCurrentImageContext();
   UIGraphicsEndImageContext();
   // 切换回主线程显示图片
   [[NSOperationQueue mainQueue] addOperation:[NSBlockOperation blockOperationWithBlock:^{
       self.imageView.image = image3;
   }]]; }]; // 设置依赖
[block3 addDependency:block1];
[block3 addDependency:block2]; // 添加任务到队列中
[queue addOperation:block1];
[queue addOperation:block2];
[queue addOperation:block3];

应用

应用:SDWebImage 框架的底层主要功能实现就是基于多线程,使用多线程,我们可以实现小图片的多图片下载。这里的逻辑其实是比较复杂的

实现小图片的多图片下载思路:

代码实现见本文代码。

iOS 之 多线程一的更多相关文章

  1. ios开发多线程一:了解-NSOperation的基本使用

    #import "ViewController.h" @interface ViewController () @end @implementation ViewControlle ...

  2. IOS 股票K线图、分时图

    IOS 股票K线图.分时图,网上开源项目很少,质量也是参差不齐:偶尔搜索到看似有希望的文章,点进去,还是个标题党:深受毒害.经过一段时间的探索,终于在开源基础上完成了自己的股票K线图.分时图: 先放出 ...

  3. 移动开发在路上-- IOS移动开发系列 多线程一

    类似于什么是进程什么是线程在这里我就不多浪费时间了(Google一下什么都有)! 废话不多说先上图,我相信大家都是喜欢看图的人,俗话说得好,求图求真相吗?虽然这里只有屌丝一个但是真相还是会有的... ...

  4. 记Booking.com iOS开发岗位线上笔试

    今晚参加了Booking的iOS职位线上笔试,结束后方能简单归纳一下. 关于测试内容: Booking采用了HackerRank作为测试平台,测试总时长为75分钟,总计4道题. 测试之前我很紧张,因为 ...

  5. YYStock开源----iOS股票K线绘制第二版

    新的股票绘制粗来啦,欢迎围观star的说(*^__^*) 嘻嘻-- 捏合功能也准备完善了 Github:https://github.com/yate1996/YYStock 长按分时图+五档图 分时 ...

  6. ios cocos2d 画线出现闪烁问题

    根据http://www.merowing.info/2012/04/drawing-smooth-lines-with-cocos2d-ios-inspired-by-paper/ 用cocos2d ...

  7. iOS开发多线程之NSThread

    一.NSThread的属性与方法 1.NSThread 类方法 类方法,顾名思义通过类名直接调用的方法 1. + (void)detachNewThreadWithBlock:(void (^)(vo ...

  8. iOS开发-多线程之GCD(Grand Central Dispatch)

    Grand Central Dispatch(GCD)是一个强有力的方式取执行多线程任务,不管你在回调的时候是异步或者同步的,可以优化应用程序支持多核心处理器和其他的对称多处理系统的系统.开发使用的过 ...

  9. C#夯实基础之多线程一:初识多线程

    一. 烧水沏茶问题       在小学四年级有一个烧水沏茶问题,可以作为我们今天讨论话题的引子: 客人来了,要烧一壶茶,但是烧水需要5分钟,洗水壶需要1分钟,洗茶杯需要2分钟,接水需要1分钟,找茶叶需 ...

随机推荐

  1. [Canvas] Introduction to drawing with p5js

    In this lesson we look at using color and the basic drawing methods of p5js, and how they can be com ...

  2. 【转】获取Sprite的实际Rect

    判断点击是否点击在了一个精灵上, 其实就是判断一个点是否在一个矩形内. cocos2d-x的2.0.2版本可以使用CCRect的函数 bool CCRect::containsPoint(const ...

  3. Java基础知识强化之IO流笔记56:IO流练习之 登录注册IO版

    1.  登录注册IO版的Java项目框架,如下: 2. 具体代码实现: (1)User.java(cn.itcast.game): package cn.itcast.pojo; /** * 这是用户 ...

  4. flex学习网站地址

    http://hacker47.iteye.com/blog/213887 http://www.cuplayer.com/player/PlayerCode/Flex/ http://bbs.9ri ...

  5. arc项目中使用非arc文件

    因为之前没有ARC机制,好多比较好的类库都是使用的非ARC,或是有些大牛还是不喜欢用ARC,封装的类也是非ARC的,想要在自己的ARC项目中使用这些非ARC类库,只需要简单的设置一下就可以了. 1.在 ...

  6. PHP中将数据库中的数据显示在网页

    最近没事把以前的东西感觉还可以的又简单的看了以下,因为还在学习新的东西,所以,发表的博客也不是很多,也许是有感而发吧. 这次讲的是mysql数据库中的数据使用php如何显示在网页中.首先,先建好自己的 ...

  7. Android开发之Intent的传值--Application

    每当我们想要将输入的值传递到多个界面时,只是使用Intent传值的话,就会有一些的弊端. 下面我就以三个页面为例,进行简单的说明一下: 思路: 1.第一个页面是客户输入相关的信息. 2.将客户输入的信 ...

  8. 【转】企业级Java应用最重要的4个性能指标

    应用性能管理(APM)是一种即时监控以实现对应用程序性能管理和故障管理的系统化解决方案.目前主要指对企业的关键业务应用进行监测.优化,最终达到提高企业应用的可靠性和质量,保证用户得到良好的服务,降低I ...

  9. react 资源汇总

    前端变化虽快,但其实一直都围绕这几个概念在转: URL - 访问什么页面 Data - 显示什么信息 View - 页面长成什么样 Action - 对页面做了什么操作 API Server - Da ...

  10. ACM——完数

    完数 时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte 总提交:1930            测试通过:413 描述 自然数中,完数寥若晨 ...