【iOS】NSOperation、NSOperationQueue

2024-05-07 00:52

本文主要是介绍【iOS】NSOperation、NSOperationQueue,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 前言
  • 一、NSOperation、NSOperationQueue 简介
  • 二、NSOperation、NSOperationQueue 操作和操作队列
  • 三、NSOperation
  • 四、NSOperationQueue
  • 五、NSOperationQueue 控制串行执行、并发执行
  • 六、 NSOperation 操作依赖
  • 七、NSOperation 优先级
  • 八、NSOperation、NSOperationQueue 线程间的通信
  • 九、NSOperation、NSOperationQueue 线程同步和线程安全
    • NSOperation、NSOperationQueue 非线程安全
    • NSOperation、NSOperationQueue 非线程安全
  • 十、NSOperation、NSOperationQueue 常用属性和方法归纳
    • NSOperation 常用属性和方法
    • NSOperationQueue 常用属性和方法


前言

寒假学习了GCD,前几天学习了NSThread,今天来学习iOS 多线程中 NSOperation、NSOperationQueue 的相关知识以及使用方法。

一、NSOperation、NSOperationQueue 简介

NSOperation、NSOperationQueue 是苹果提供给我们的一套多线程解决方案。
实际上 NSOperationNSOperationQueue 是基于 GCD 更高一层的封装,完全面向对象。但是比 GCD 更简单易用、代码可读性也更高。

NSOperation需要配合NSOperationQueue来实现多线程。

二、NSOperation、NSOperationQueue 操作和操作队列

由于NSOperation、NSOperationQueue 是GCD的更高级的封装,因此两者有一些相同的概念

  • 操作(Operation)
    执行操作,也就相当于我们在线程中执行的代码
    在GCD操作是放在Block中的,在 NSOperation 中,我们使用 NSOperation 子类 NSInvocationOperation、NSBlockOperation,或者自定义子类来封装操作
  • 操作队列(Operation Queues)
  • 这里的队列是指操作队列,即用来存放操作的队列。不同于GCD的先进先出,NSOperationQueue可以设置操作执行的优先级
  • 操作队列通过设置最大并发操作数(maxConcurrentOperationCount) 来控制并发、串行。
  • NSOperationQueue 为我们提供了两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。

三、NSOperation

NSOperatino实现多线程的步骤如下:

  • 1、创建任务:先将需要执行的操作封装到NSOperation对象中。
  • 2、创建队列:创建NSOperationQueue
  • 3、将任务加入到队列中:将NSOperation对象添加到NSOperationQueue

在不使用 NSOperationQueue,单独使用 NSOperation 的情况下系统同步执行操作

- (void)applicationDidFinishLaunching:(UIApplication *)application {MyOperation *operation = [[MyOperation alloc] init];NSLog(@"Before operation start");[operation start];NSLog(@"After operation finish");
}

操作从开始到结束的输出都是按顺序且同步的。应用的执行将在 Before operation start 打印后直接开始 NSOperation,然后直到该操作完成后,才继续执行打印 After operation finish。由于 start 方法是同步执行的,所以它会阻塞当前线程直到操作完成。

//基本使用
- (void)testBaseNSOperation{//处理事务NSInvocationOperation *op =  [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(handleInvocation:) object:@"XN"]; // object是传递参数NSOperationQueue *queue = [[NSOperationQueue alloc] init];//操作加入队列[queue addOperation:op];   
}
- (void)handleInvocation:(id)operation{NSLog(@"%@ - %@", operation, [NSThread currentThread]);
}

NSOperation是个抽象类,实际运用时中需要使用它的子类

  • 1、使用子类NSInvocationOperation
//直接处理事务,不添加隐性队列
- (void)createNSOperation{//创建NSInvocationOperation对象并关联方法,之后start。NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomething:) object:@"xn"];[invocationOperation start];
}

在这里插入图片描述

当我们直接使用[invocationOperation start];时任务在主线程执行

  • 2、使用子类NSBlockOperation
- (void)useBlockOperation {// 1.创建 NSBlockOperation 对象NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];// 2.调用 start 方法开始执行操作[op start];
}

在这里插入图片描述
在没有使用NSOperationQueue,同时没有使用addExecutionBlock方法时不会开启新线程执行操作

同时通过addExecutionBlock就可以开启新线程执行操作

如果添加的操作多的话, blockOperationWithBlock: 中的操作也可能会在其他线程(非当前主线程)中执行,这是由系统决定的

- (void)testNSBlockOperationExecution{// 1.创建 NSBlockOperation 对象NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];// 2.添加额外的操作[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"5---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"6---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"7---%@", [NSThread currentThread]); // 打印当前线程}}];[op addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"8---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.调用 start 方法开始执行操作[op start];
}

输出:
在这里插入图片描述
使用子类 NSBlockOperation,并调用方法 AddExecutionBlock: 的情况下,blockOperationWithBlock:方法中的操作 和 addExecutionBlock: 中的操作是在不同的线程中异步执行的

  • 3、定义继承自NSOperation的子类,通过实现内部相应的方法来封装任务。
//*********自定义继承自NSOperation的子类*********
@interface CJLOperation : NSOperation
@end@implementation CJLOperation
- (void)main{for (int i = 0; i < 3; i++) {NSLog(@"NSOperation的子类:%@",[NSThread currentThread]);}
}
@end//*********使用*********
- (void)cjl_testCJLOperation{//运用继承自NSOperation的子类 首先我们定义一个继承自NSOperation的类,然后重写它的main方法。CJLOperation *operation = [[CJLOperation alloc] init];[operation start];
}

输出:
在这里插入图片描述
可以看出:在没有使用 NSOperationQueue、在主线程单独使用自定义继承自 NSOperation 的子类的情况下,是在主线程执行操作,并没有开启新线程

四、NSOperationQueue

NSOperationQueue添加事务
NSOperationQueue有两种队列:主队列、其他队列。其他队列包含了 串行和并发

  • 主队列
    凡是添加到主队列中的操作,都会放到主线程中执行。
// 主队列获取方法
NSOperationQueue *queue = [NSOperationQueue mainQueue];
  • 自定义队列(非主队列)
    添加到这种队列中的操作,就会自动放到子线程中执行
    同时包含了:串行、并发功能。
// 自定义队列创建方法
NSOperationQueue *queue = [[NSOperationQueue alloc] init];

将操作加入到队列中

上边我们说到 NSOperation 需要配合 NSOperationQueue 来实现多线程。

那么我们需要将创建好的操作加入到队列中去。总共有两种方法:
1、- (void)addOperation:(NSOperation *)op;
需要先创建操作,再将创建好的操作加入到创建好的队列中去。

/*** 使用 addOperation: 将操作加入到操作队列中*/
- (void)addOperationToQueue {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.创建操作// 使用 NSInvocationOperation 创建操作1NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task1) object:nil];// 使用 NSInvocationOperation 创建操作2NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task2) object:nil];// 使用 NSBlockOperation 创建操作3NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[op3 addExecutionBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.使用 addOperation: 添加所有操作到队列中[queue addOperation:op1]; // [op1 start][queue addOperation:op2]; // [op2 start][queue addOperation:op3]; // [op3 start]
}

使用 NSOperation 子类创建操作,并使用 addOperation: 将操作加入到操作队列后能够开启新线程,进行并发执行

NSOperationQueue 管理一个或多个 NSOperation 对象的执行。当你将 NSOperation 实例加入到 NSOperationQueue 时,你不需要手动创建和管理线程。操作队列自动处理这些细节。

2、- (void)addOperationWithBlock:(void (^)(void))block;
无需先创建操作,在 block 中添加操作,程序直接将包含操作的 block 加入到队列中

/*** 使用 addOperationWithBlock: 将操作加入到操作队列中*/- (void)addOperationWithBlockToQueue {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.使用 addOperationWithBlock: 添加操作到队列中[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];
}

在这里插入图片描述
可以看出:使用 addOperationWithBlock: 将操作加入到操作队列后能够开启新线程,进行并发执行

五、NSOperationQueue 控制串行执行、并发执行

我们在上面演示了并发功能,我们来看一下它的串行功能如何实现

这里有个关键属性 maxConcurrentOperationCount ,叫做最大并发操作数。用来控制一个特定队列中可以有多少个操作同时参与并发执行。

注意:这里 maxConcurrentOperationCount 控制的不是并发线程的数量,而是一个队列中同时能并发执行的最大操作数。而且一个操作也并非只能在一个线程中运行,一个操作可能很长,可以将其分散在多个线程中执行,比如我们在子线程更新数据后在主线程更新UI。

最大并发操作数:maxConcurrentOperationCount

maxConcurrentOperationCount 默认情况下为-1,表示不进行限制,可进行并发执行
maxConcurrentOperationCount 为1时,队列为串行队列。只能串行执行。
maxConcurrentOperationCount 大于1时,队列为并发队列。操作并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整为 min{自己设定的值,系统设定的默认最大值}。

/*** 设置 MaxConcurrentOperationCount(最大并发操作数)*/
- (void)setMaxConcurrentOperationCount {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.设置最大并发操作数queue.maxConcurrentOperationCount = 1; // 串行队列
// queue.maxConcurrentOperationCount = 2; // 并发队列
// queue.maxConcurrentOperationCount = 8; // 并发队列// 3.添加操作[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程}}];[queue addOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程}}];
}

maxConcurrentOperationCount = 1
在这里插入图片描述

可以看到任务按顺序串行执行

maxConcurrentOperationCount = 2

在这里插入图片描述
并发操作数为2时可以执行两个操作,操作时并发施行的,而开启线程数量是由系统决定的,不需要我们来管理。

因为NSOperation由系统控制开启线程数量以及串行并行,而GCD需要我们手动控制

六、 NSOperation 操作依赖

NSOperation、NSOperationQueue 最吸引人的地方是它能添加操作之间的依赖关系。通过操作依赖,我们可以很方便的控制操作之间的执行先后顺序。NSOperation 提供了3个接口供我们管理和查看依赖。

  • (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
  • (void)removeDependency:(NSOperation *)op; 移除依赖,取消当前操作对操作 op 的依赖。
  • @property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。

我们现在来假设一个场景,有两个操作A、B,A操作完B才能操作,也就是B依赖A

/*** 操作依赖* 使用方法:addDependency:*/
- (void)addDependency {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc] init];// 2.创建操作NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}}];NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];// 3.添加依赖[op2 addDependency:op1]; // 让op2 依赖于 op1,则先执行op1,在执行op2// 4.添加操作到队列中[queue addOperation:op2];[queue addOperation:op1];
}

可以看到即使两个操作在不同线程执行也就是并发执行,也是op1先执行才能执行op2
在这里插入图片描述
去掉依赖:
在这里插入图片描述

七、NSOperation 优先级

NSOperation 提供了queuePriority(优先级)属性,queuePriority属性适用于同一操作队列中的操作

默认情况下,所有新创建的操作对象优先级都是NSOperationQueuePriorityNormal,但是我们可以通过setQueuePriority:方法来改变当前操作在同一队列中的执行优先级

// 优先级的取值
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {NSOperationQueuePriorityVeryLow = -8L,NSOperationQueuePriorityLow = -4L,NSOperationQueuePriorityNormal = 0,NSOperationQueuePriorityHigh = 4,NSOperationQueuePriorityVeryHigh = 8
};

将操作添加到队列后操作会进入就绪状态,就绪状态的操作的执行顺序由操作之间的优先级决定

就绪状态的操作:简单理解就是准备就绪的操作就是没有需要依赖的操作,例如op2依赖于op1,那么op2就没有准备就绪,因为他需要等op1执行完才准备就绪

优先级不能取代依赖关系。如果要控制操作间的启动顺序,则必须使用依赖关系。

八、NSOperation、NSOperationQueue 线程间的通信

同样的我们在开发中常常在子线程中更新数据在主线程中更新UI,这在NSOperation中时如何实现的呢

/*** 线程间通信*/
- (void)communication {// 1.创建队列NSOperationQueue *queue = [[NSOperationQueue alloc]init];// 2.添加操作[queue addOperationWithBlock:^{// 异步进行耗时操作for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程}// 回到主线程[[NSOperationQueue mainQueue] addOperationWithBlock:^{// 进行一些 UI 刷新等操作for (int i = 0; i < 2; i++) {[NSThread sleepForTimeInterval:2]; // 模拟耗时操作NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程}}];}];
}

输出:
在这里插入图片描述

九、NSOperation、NSOperationQueue 线程同步和线程安全

又到了老生常谈的售票问题

NSOperation、NSOperationQueue 非线程安全

因为使用NSOperation将操作添加到队列时系统后自动执行并发操作
因此如果不对线程进行加锁会出现如下状况

/*** 非线程安全:不使用 NSLock* 初始化火车票数量、卖票窗口(非线程安全)、并开始卖票*/
- (void)initTicketStatusNotSave {NSLog(@"currentThread---%@",[NSThread currentThread]); // 打印当前线程self.ticketSurplusCount = 50;// 1.创建 queue1,queue1 代表北京火车票售卖窗口NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];queue1.maxConcurrentOperationCount = 1;// 2.创建 queue2,queue2 代表上海火车票售卖窗口NSOperationQueue *queue2 = [[NSOperationQueue alloc] init];queue2.maxConcurrentOperationCount = 1;// 3.创建卖票操作 op1__weak typeof(self) weakSelf = self;NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{[weakSelf saleTicketNotSafe];}];// 4.创建卖票操作 op2NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{[weakSelf saleTicketNotSafe];}];// 5.添加操作,开始卖票[queue1 addOperation:op1];[queue2 addOperation:op2];
}/*** 售卖火车票(非线程安全)*/
- (void)saleTicketNotSafe {while (1) {if (self.ticketSurplusCount > 0) {//如果还有票,继续售卖self.ticketSurplusCount--;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);[NSThread sleepForTimeInterval:0.2];} else {NSLog(@"所有火车票均已售完");break;}}
}

输出:
在这里插入图片描述

NSOperation、NSOperationQueue 非线程安全

使用互斥锁进行加锁后就得到了正确的票数

- (void)saleTicketNotSafe {while (1) {@synchronized (self) {if (self.ticketSurplusCount > 0) {//如果还有票,继续售卖self.ticketSurplusCount--;NSLog(@"%@", [NSString stringWithFormat:@"剩余票数:%d 窗口:%@", self.ticketSurplusCount, [NSThread currentThread]]);[NSThread sleepForTimeInterval:0.2];} else {NSLog(@"所有火车票均已售完");break;}}}
}

输出:
在这里插入图片描述

十、NSOperation、NSOperationQueue 常用属性和方法归纳

NSOperation 常用属性和方法

取消操作方法

  • - (void)cancel; 可取消操作,实质是标记 isCancelled 状态。

判断操作状态方法

  • - (BOOL)isFinished; 判断操作是否已经结束。
  • - (BOOL)isCancelled; 判断操作是否已经标记为取消。
  • - (BOOL)isExecuting; 判断操作是否正在在运行。
  • - (BOOL)isReady; 判断操作是否处于准备就绪状态,这个值和操作的依赖关系相关。

操作同步

  • -(void)waitUntilFinished; 阻塞当前线程,直到该操作结束。可用于线程执行顺序的同步。
  • - (void)setCompletionBlock:(void (^)(void))block; completionBlock 会在当前操作执行完毕时执行 completionBlock。
  • - (void)addDependency:(NSOperation *)op; 添加依赖,使当前操作依赖于操作 op 的完成。
  • - (void)removeDependency:(NSOperation *)op;移除依赖,取消当前操作对操作 op 的依赖。
  • @property (readonly, copy) NSArray<NSOperation *> *dependencies; 在当前操作开始执行之前完成执行的所有操作对象数组。

NSOperationQueue 常用属性和方法

取消/暂停/恢复操作

- (void)cancelAllOperations; 可以取消队列的所有操作。
- (BOOL)isSuspended; 判断队列是否处于暂停状态。 YES 为暂停状态,NO 为恢复状态。
- (void)setSuspended:(BOOL)b; 可设置操作的暂停和恢复,YES 代表暂停队列,NO 代表恢复队列。

操作同步

- (void)waitUntilAllOperationsAreFinished; 阻塞当前线程,直到队列中的操作全部执行完毕。

添加/获取操作

- (void)addOperationWithBlock:(void (^)(void))block; 向队列中添加一个 NSBlockOperation 类型操作对象。
- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait; 向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束
- (NSArray *)operations; 当前在队列中的操作数组(某个操作执行结束后会自动从这个数组清除)。
- (NSUInteger)operationCount; 当前队列中的操作数。

获取队列

+ (id)currentQueue; 获取当前队列,如果当前线程不是在 NSOperationQueue 上运行则返回 nil。
+ (id)mainQueue; 获取主队列。

这篇关于【iOS】NSOperation、NSOperationQueue的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/965873

相关文章

安卓链接正常显示,ios#符被转义%23导致链接访问404

原因分析: url中含有特殊字符 中文未编码 都有可能导致URL转换失败,所以需要对url编码处理  如下: guard let allowUrl = webUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {return} 后面发现当url中有#号时,会被误伤转义为%23,导致链接无法访问

【iOS】MVC模式

MVC模式 MVC模式MVC模式demo MVC模式 MVC模式全称为model(模型)view(视图)controller(控制器),他分为三个不同的层分别负责不同的职责。 View:该层用于存放视图,该层中我们可以对页面及控件进行布局。Model:模型一般都拥有很好的可复用性,在该层中,我们可以统一管理一些数据。Controlller:该层充当一个CPU的功能,即该应用程序

iOS剪贴板同步到Windows剪贴板(无需安装软件的方案)

摘要 剪贴板同步能够提高很多的效率,免去复制、发送、复制、粘贴的步骤,只需要在手机上复制,就可以直接在电脑上 ctrl+v 粘贴,这方面在 Apple 设备中是做的非常好的,Apple 设备之间的剪贴板同步功能(Universal Clipboard)确实非常方便,它可以在 iPhone、iPad 和 Mac 之间无缝传输剪贴板内容,从而大大提高工作效率。 但是,iPhone 如何和 Wind

iOS项目发布提交出现invalid code signing entitlements错误。

1、进入开发者账号,选择App IDs,找到自己项目对应的AppId,点击进去编辑, 2、看下错误提示出现  --Specifically, value "CVYZ6723728.*" for key "com.apple.developer.ubiquity-container-identifiers" in XX is not supported.-- 这样的错误提示 将ubiquity

我的第一次份实习工作-iOS实习生-第三个月

第三个月 这个月有一个考核项目,是一个电子书阅读器,组长说很重要,是我的实习考核项目。 我的项目XTReader,这是我参考网上的一些代码,和模仿咪咕阅读做的,功能还不完善,数据的部分是用聚合数据做的。要收费的。   还有阅读页面,基本功能实现了一下。使用了autolayout,自适应布局,也是第一次用网络,第一次用数据库,第一次用自动布局。还有很多不足。 做了一周多,有个问题一直没

我的第一次份实习工作-iOS实习生-公司使用过的软件

bittorrentsync 素材,文件同步软件 cornerstone svn 软件开发合作 mark man 测量坐标的软件 SQLLite Manager 数据库操作软件

我的第一次份实习工作-iOS实习生-第二个月

第二个月 来公司过了一个月了。每天早上9点上班,到晚上6.30下班,上下班要指纹打卡,第一个月忘了打卡好多次(),然后还要去补打卡单。公司这边还安排了,工资卡办理,招商银行卡。开了一次新员工大会,认识了公司的一些过往,公司的要求等,还加了一下公司的企业QQ,还有其他的羽毛球群,篮球群。我加了下羽毛球群,也去打了一两次。第二个月的感受,感觉跟组里面的交流跟沟通都好少,基本上还有好多人不认识。想想也

我的第一次份实习工作-iOS实习生-第一个月

实习时间:2015-08-20 到 2015-12-25  实习公司;福建天棣互联有限公司 实习岗位:iOS开发实习生 第一个月: 第一天来公司,前台报道后,人资带我去我工作的地方。到了那,就由一个组长带我,当时还没有我的办公桌,组长在第三排给我找了一个位置,擦了下桌子,把旁边的准备的电脑帮我装了下,因为学的是iOS,实习生就只能用黑苹果了,这是我实习用的电脑。 帮我装了一下电脑后,开机

iOS如何隐藏系统状态栏

这里主要说明一下iOS7系统给状态栏的适配及隐藏带来的改变。 变化一: 不隐藏状态栏的情况下,StatusBar会直接显示在当前页面上,当前页面的会延伸到 StatusBar下方,顶到最上头。 这种显示方式在iOS7上是无法改变的,也无法通过设置或者配置类达到iOS6的状态栏效果。       所以在iOS7上进行页面布局的时候要考虑

ios %.2f是四舍五入吗?

实事上这个“四舍五入”并不是数学上的“四舍五入”,而是“四舍六入五成双”,英文中被称为”round half to even”或”Banker’s rounding”。 “四舍六入五成双”是指,当保留精度的下一位不是5时,按正常的四舍五入;当保留精度的下一位是5时,如果5的后面为0则舍弃;而如果5的后面还有大于0的部分时,则无论5的前一位是奇数还是偶数,都进行进位。 1.当保留精度的下一位不是