多线程开发之二 NSOperation

效果如下:

ViewController.h

1 #import <UIKit/UIKit.h>
2
3 @interface ViewController : UITableViewController
4 @property (strong, nonatomic) NSArray *arrSampleName;
5
6 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName;
7
8 @end 

ViewController.m

 1 #import "ViewController.h"
 2 #import "FirstSampleViewController.h"
 3 #import "SecondSampleViewController.h"
 4
 5 @interface ViewController ()
 6 - (void)layoutUI;
 7 @end
 8
 9 @implementation ViewController
10 - (void)viewDidLoad {
11     [super viewDidLoad];
12
13     [self layoutUI];
14 }
15
16 - (void)didReceiveMemoryWarning {
17     [super didReceiveMemoryWarning];
18     // Dispose of any resources that can be recreated.
19 }
20
21 - (instancetype)initWithSampleNameArray:(NSArray *)arrSampleName {
22     if (self = [super initWithStyle:UITableViewStyleGrouped]) {
23         self.navigationItem.title = @"多线程开发之二 NSOperation";
24         self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"返回首页" style:UIBarButtonItemStylePlain target:nil action:nil];
25
26         _arrSampleName = arrSampleName;
27     }
28     return self;
29 }
30
31 - (void)layoutUI {
32 }
33
34 #pragma mark - UITableViewController相关方法重写
35 - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
36     return 0.1;
37 }
38
39 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
40     return 1;
41 }
42
43 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
44     return [_arrSampleName count];
45 }
46
47 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
48     static NSString *cellIdentifier = @"cell";
49     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
50     if (!cell) {
51         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
52     }
53     cell.textLabel.text = _arrSampleName[indexPath.row];
54     return cell;
55 }
56
57 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
58     switch (indexPath.row) {
59         case 0: {
60             FirstSampleViewController *firstSampleVC = [FirstSampleViewController new];
61             [self.navigationController pushViewController:firstSampleVC animated:YES];
62             break;
63         }
64         case 1: {
65             SecondSampleViewController *secondSampleVC = [SecondSampleViewController new];
66             [self.navigationController pushViewController:secondSampleVC animated:YES];
67             break;
68         }
69         default:
70             break;
71     }
72 }
73
74 @end 

UIImage+RescaleImage.h

 1 #import <UIKit/UIKit.h>
 2
 3 @interface UIImage (RescaleImage)
 4 /**
 5  *  根据宽高大小,获取对应的缩放图片
 6  *
 7  *  @param size 宽高大小
 8  *
 9  *  @return 对应的缩放图片
10  */
11 - (UIImage *)rescaleImageToSize:(CGSize)size;
12
13 @end 

UIImage+RescaleImage.m

 1 #import "UIImage+RescaleImage.h"
 2
 3 @implementation UIImage (RescaleImage)
 4
 5 - (UIImage *)rescaleImageToSize:(CGSize)size {
 6     CGRect rect = CGRectMake(0.0, 0.0, size.width, size.height);
 7
 8     UIGraphicsBeginImageContext(rect.size);
 9     [self drawInRect:rect];
10     UIImage *imgScale = UIGraphicsGetImageFromCurrentImageContext();
11     UIGraphicsEndImageContext();
12
13     return imgScale;
14 }
15
16 @end 

Common.h

1 #import <Foundation/Foundation.h>
2
3 @interface Common : NSObject
4 + (NSURL *)randomImageURL;
5
6 @end 

Common.m

 1 #import "Common.h"
 2
 3 @implementation Common
 4
 5 + (NSURL *)randomImageURL {
 6     NSUInteger randomVal = (arc4random() % 20) + 1; //1-20的随机数
 7     NSString *randomValStr = [NSString stringWithFormat:@"%lu", (unsigned long)randomVal];
 8     if (randomVal < 10) {
 9         randomValStr = [@"0" stringByAppendingString:randomValStr];
10     }
11
12     NSString *imageURLStr = [NSString stringWithFormat:@"http://images.apple.com/v/watch/e/apple-watch/images/collection_%@_large.jpg", randomValStr];
13     return [NSURL URLWithString:imageURLStr];
14 }
15
16 @end 

FirstSampleViewController.h

1 #import <UIKit/UIKit.h>
2
3 @interface FirstSampleViewController : UIViewController
4 @property (assign, nonatomic) CGSize rescaleImageSize;
5
6 @property (strong, nonatomic) IBOutlet UIImageView *imgV;
7 @property (strong, nonatomic) IBOutlet UIButton *btnLoadImage;
8
9 @end 

FirstSampleViewController.m

 1 #import "FirstSampleViewController.h"
 2 #import "UIImage+RescaleImage.h"
 3 #import "Common.h"
 4
 5 @interface FirstSampleViewController ()
 6 - (void)layoutUI;
 7 - (void)updateImage:(NSData *)imageData;
 8 - (void)loadImageFromNetwork;
 9 @end
10
11 @implementation FirstSampleViewController
12
13 - (void)viewDidLoad {
14     [super viewDidLoad];
15
16     [self layoutUI];
17 }
18
19 - (void)didReceiveMemoryWarning {
20     [super didReceiveMemoryWarning];
21     // Dispose of any resources that can be recreated.
22 }
23
24 - (void)dealloc {
25     _imgV.image = nil;
26 }
27
28 - (void)layoutUI {
29     CGFloat width = [[UIScreen mainScreen] bounds].size.width; //bounds 返回整个屏幕大小;applicationFrame 返回去除状态栏后的屏幕大小
30     CGFloat height = width * 438.0 / 366.0;
31     const CGFloat percentVal = 3.0 / 4.0; //以屏幕宽度的3/4比例显示
32     _rescaleImageSize = CGSizeMake(width * percentVal, height * percentVal);
33
34     //NSString *path = [[NSBundle mainBundle] pathForResource:@"[email protected]" ofType:@"png"];
35     //_imgV.image = [UIImage imageWithContentsOfFile:path];
36
37     _btnLoadImage.tintColor = [UIColor darkGrayColor];
38     _btnLoadImage.layer.masksToBounds = YES;
39     _btnLoadImage.layer.cornerRadius = 10.0;
40     _btnLoadImage.layer.borderColor = [UIColor grayColor].CGColor;
41     _btnLoadImage.layer.borderWidth = 1.0;
42 }
43
44 - (void)updateImage:(NSData *)imageData {
45     UIImage *img = [UIImage imageWithData:imageData];
46     _imgV.image = [img rescaleImageToSize:_rescaleImageSize];
47 }
48
49 - (void)loadImageFromNetwork {
50     NSURL *url = [Common randomImageURL];
51     NSData *data = [NSData dataWithContentsOfURL:url];
52
53     //mainQueue 是 UI 主线程,调用主线程队列的方法进行操作
54     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
55         [self updateImage:data];
56     }];
57 }
58
59 - (IBAction)loadImage:(id)sender {
60     //方法一:使用 NSInvocationOperation
61 //    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]
62 //                                                  initWithTarget:self
63 //                                                  selector:@selector(loadImageFromNetwork)
64 //                                                  object:nil];
65 //    NSOperationQueue *operationQueue = [NSOperationQueue new]; //操作队列
66 //    [operationQueue addOperation:invocationOperation];
67
68
69     //方法二:使用 NSBlockOperation
70     NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
71         [self loadImageFromNetwork];
72     }];
73     [blockOperation addExecutionBlock:^{ //还可以为 blockOperation 添加代码块;多个代码块会被分到多个线程去执行,存在两个代码块被分配到同一个线程执行的情况
74         NSLog(@"代码块");
75     }];
76     [blockOperation addExecutionBlock:[blockOperation executionBlocks][1]]; //这里可以调用他的 executionBlocks 获取到添加的代码块数组;上面打印的内容「代码块」会被执行两次
77
78     [blockOperation setCompletionBlock:^{
79         NSLog(@"所有代码块操作执行完毕后(无论已取消还是已完成),做一些事情,只执行一次");
80     }];
81
82     //[blockOperation start]; //使用 start 方法,则此操作在主线程中执行;一般不这样操作,而是添加到操作队列中
83     NSOperationQueue *operationQueue = [NSOperationQueue new]; //操作队列
84     [operationQueue addOperation:blockOperation]; //添加到操作队列,这时队列会开启一个线程去执行此操作;一个线程可以执行多个操作
85
86     //方法三:直接使用 NSOperationQueue
87 //    NSOperationQueue *operationQueue = [NSOperationQueue new]; //操作队列
88 //    [operationQueue addOperationWithBlock:^{
89 //        [self loadImageFromNetwork];
90 //    }];
91 }
92
93 @end 

FirstSampleViewController.xib

 1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
 3     <dependencies>
 4         <deployment identifier="iOS"/>
 5         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
 6     </dependencies>
 7     <objects>
 8         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File‘s Owner" customClass="FirstSampleViewController">
 9             <connections>
10                 <outlet property="btnLoadImage" destination="sLs-f1-Gzc" id="kX8-J0-v0V"/>
11                 <outlet property="imgV" destination="4Qp-uk-KAb" id="RM3-Ha-glh"/>
12                 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
13             </connections>
14         </placeholder>
15         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
16         <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
17             <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
18             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
19             <subviews>
20                 <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="PictureNo.png" translatesAutoresizingMaskIntoConstraints="NO" id="4Qp-uk-KAb">
21                     <rect key="frame" x="205" y="225" width="190" height="150"/>
22                     <constraints>
23                         <constraint firstAttribute="height" constant="150" id="SIp-Wd-idU"/>
24                         <constraint firstAttribute="height" constant="150" id="VwM-i1-atB"/>
25                         <constraint firstAttribute="width" constant="190" id="mUh-Bu-tUd"/>
26                         <constraint firstAttribute="width" constant="190" id="mdJ-1c-QFa"/>
27                         <constraint firstAttribute="width" constant="190" id="sVS-bU-Ty9"/>
28                         <constraint firstAttribute="height" constant="150" id="uMG-oN-J56"/>
29                         <constraint firstAttribute="height" constant="150" id="vws-Qw-UrB"/>
30                     </constraints>
31                     <variation key="default">
32                         <mask key="constraints">
33                             <exclude reference="SIp-Wd-idU"/>
34                             <exclude reference="VwM-i1-atB"/>
35                             <exclude reference="mUh-Bu-tUd"/>
36                             <exclude reference="mdJ-1c-QFa"/>
37                             <exclude reference="sVS-bU-Ty9"/>
38                             <exclude reference="uMG-oN-J56"/>
39                             <exclude reference="vws-Qw-UrB"/>
40                         </mask>
41                     </variation>
42                 </imageView>
43                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="sLs-f1-Gzc">
44                     <rect key="frame" x="230" y="500" width="140" height="50"/>
45                     <constraints>
46                         <constraint firstAttribute="width" constant="140" id="1jv-9K-mdH"/>
47                         <constraint firstAttribute="height" constant="50" id="Q2w-vR-9ac"/>
48                     </constraints>
49                     <state key="normal" title="加载网络图片">
50                         <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
51                     </state>
52                     <connections>
53                         <action selector="loadImage:" destination="-1" eventType="touchUpInside" id="fdy-Ln-5oS"/>
54                     </connections>
55                 </button>
56             </subviews>
57             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
58             <constraints>
59                 <constraint firstItem="4Qp-uk-KAb" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="leading" constant="205" id="2a2-mS-WFa"/>
60                 <constraint firstItem="sLs-f1-Gzc" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="ES4-wl-RBz"/>
61                 <constraint firstItem="4Qp-uk-KAb" firstAttribute="centerY" secondItem="i5M-Pr-FkT" secondAttribute="centerY" id="MUJ-WA-sUf"/>
62                 <constraint firstItem="4Qp-uk-KAb" firstAttribute="centerX" secondItem="sLs-f1-Gzc" secondAttribute="centerX" id="Q8a-1k-DzJ"/>
63                 <constraint firstAttribute="bottom" secondItem="4Qp-uk-KAb" secondAttribute="bottom" constant="71" id="V0a-9y-Dwa"/>
64                 <constraint firstAttribute="bottom" secondItem="sLs-f1-Gzc" secondAttribute="bottom" constant="50" id="VMG-CV-eeq"/>
65                 <constraint firstItem="4Qp-uk-KAb" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="-71" id="gqW-Wq-4Zv"/>
66                 <constraint firstItem="sLs-f1-Gzc" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="kNf-6d-EJ8"/>
67             </constraints>
68             <variation key="default">
69                 <mask key="constraints">
70                     <exclude reference="2a2-mS-WFa"/>
71                     <exclude reference="V0a-9y-Dwa"/>
72                     <exclude reference="gqW-Wq-4Zv"/>
73                     <exclude reference="ES4-wl-RBz"/>
74                 </mask>
75             </variation>
76         </view>
77     </objects>
78     <resources>
79         <image name="PictureNo.png" width="190" height="150"/>
80     </resources>
81 </document> 

SecondSampleViewController.h

1 #import <UIKit/UIKit.h>
2
3 @interface SecondSampleViewController : UIViewController
4 @property (assign, nonatomic) CGSize rescaleImageSize;
5 @property (strong, nonatomic) NSMutableArray *mArrImageView;
6
7 @property (strong, nonatomic) IBOutlet UIButton *btnLoadImage;
8
9 @end 

SecondSampleViewController.m

  1 #import "SecondSampleViewController.h"
  2 #import "UIImage+RescaleImage.h"
  3 #import "Common.h"
  4
  5 #define kRowCount 4
  6 #define kColumnCount 3
  7 #define kCellSpacing 10.0
  8
  9 @interface SecondSampleViewController ()
 10 - (void)layoutUI;
 11 - (void)updateImage:(NSData *)imageData withImageIndex:(NSInteger)imageIndex;
 12 -(NSData *)requestData:(NSInteger)imageIndex;
 13 - (void)loadImageFromNetwork:(NSInteger)imageIndex;
 14 @end
 15
 16 @implementation SecondSampleViewController
 17
 18 - (void)viewDidLoad {
 19     [super viewDidLoad];
 20
 21     [self layoutUI];
 22 }
 23
 24 - (void)didReceiveMemoryWarning {
 25     [super didReceiveMemoryWarning];
 26     // Dispose of any resources that can be recreated.
 27 }
 28
 29 - (void)dealloc {
 30     _mArrImageView = nil;
 31 }
 32
 33 - (void)layoutUI {
 34     CGFloat width = ([[UIScreen mainScreen] bounds].size.width - ((kColumnCount + 1) * kCellSpacing)) / kColumnCount;
 35     _rescaleImageSize = CGSizeMake(width, width);
 36
 37     CGFloat heightOfStatusAndNav = 20.0 + 44.0;
 38     NSString *path = [[NSBundle mainBundle] pathForResource:@"[email protected]" ofType:@"png"];
 39     UIImage *img = [UIImage imageWithContentsOfFile:path];
 40     _mArrImageView = [NSMutableArray arrayWithCapacity:kRowCount * kColumnCount];
 41     //初始化多个图片视图
 42     for (NSUInteger i=0; i<kRowCount; i++) {
 43         for (NSUInteger j=0; j<kColumnCount; j++) {
 44             UIImageView *imgV = [[UIImageView alloc] initWithFrame:
 45                                  CGRectMake(_rescaleImageSize.width * j + kCellSpacing * (j+1),
 46                                             _rescaleImageSize.height * i + kCellSpacing * (i+1) + heightOfStatusAndNav,
 47                                             _rescaleImageSize.width,
 48                                             _rescaleImageSize.height)];
 49             imgV.image = img;
 50             [self.view addSubview:imgV];
 51             [_mArrImageView addObject:imgV];
 52         }
 53     }
 54
 55     _btnLoadImage.tintColor = [UIColor darkGrayColor];
 56     _btnLoadImage.layer.masksToBounds = YES;
 57     _btnLoadImage.layer.cornerRadius = 10.0;
 58     _btnLoadImage.layer.borderColor = [UIColor grayColor].CGColor;
 59     _btnLoadImage.layer.borderWidth = 1.0;
 60 }
 61
 62 - (void)updateImage:(NSData *)imageData withImageIndex:(NSInteger)imageIndex {
 63     UIImage *img = [UIImage imageWithData:imageData];
 64     UIImageView *imgVCurrent = _mArrImageView[imageIndex];
 65     imgVCurrent.image = [img rescaleImageToSize:_rescaleImageSize];
 66 }
 67
 68 -(NSData *)requestData:(NSInteger)imageIndex {
 69     //对于多线程操作,建议把线程操作放到 @autoreleasepool 中
 70     @autoreleasepool {
 71         NSURL *url = [Common randomImageURL];
 72         NSData *data = [NSData dataWithContentsOfURL:url];
 73         return data;
 74     }
 75 }
 76
 77 - (void)loadImageFromNetwork:(NSInteger)imageIndex {
 78     /*
 79      对比之前 NSThread 加载图片,你会发现核心代码简化了不少,有两点值得提的:
 80      (1)使用 NSBlockOperation 方法,所有的操作不必单独定义方法,同时解决了只能传递一个参数的问题。类似的操作,例如:调用主线程队列的 addOperationWithBlock: 方法进行 UI 更新,不用再定义一个参数实体类来进行参数传递(之前必须定义一个 KMImageData 解决只能传递一个参数的问题)。
 81      (2)使用 NSOperation 进行多线程开发可以设置最大并发操作数,有效的对操作进行控制(如 Demo 的代码设置最大并发操作数为5,则图片最多是五个一次加载的)。
 82      */
 83     NSLog(@"Current thread:%@", [NSThread currentThread]);
 84
 85     //mainQueue 是 UI 主线程,调用主线程队列的方法进行操作
 86     [[NSOperationQueue mainQueue] addOperationWithBlock:^{
 87         [self updateImage:[self requestData:imageIndex] withImageIndex:imageIndex];
 88     }];
 89 }
 90
 91 - (IBAction)loadImage:(id)sender {
 92     NSOperationQueue *operationQueue = [NSOperationQueue new];
 93     operationQueue.maxConcurrentOperationCount = 5; //设置最大并发操作数
 94
 95     NSUInteger len = kRowCount * kColumnCount;
 96     NSBlockOperation *lastBlockOperation = [NSBlockOperation blockOperationWithBlock:^{
 97         [self loadImageFromNetwork:len - 1];
 98     }];
 99
100     for (NSUInteger i=0; i<len - 1; i++) {
101         NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
102             [self loadImageFromNetwork:i];
103         }];
104
105         //实现控制「操作执行顺序」,例如:控制最后一个操作第一个执行,这里设置操作的依赖关系为:最后一张图片加载操作完成后才执行
106         //PS:注意请勿进行循环依赖,否则循环依赖相关的操作是不会被执行的
107         //这里添加依赖关系;其相对应的移除方法:- (void)removeDependency:(NSOperation *)op;
108         [blockOperation addDependency:lastBlockOperation];
109
110         //另外添加操作对象实例数组的方法:- (void)addOperations:(NSArray *)ops waitUntilFinished:(BOOL)wait;
111         [operationQueue addOperation:blockOperation];
112     }
113
114     [operationQueue addOperation:lastBlockOperation];
115
116     /*
117     lastBlockOperation.queuePriority = NSOperationQueuePriorityVeryHigh; //在某个操作队列中的队列优先级;这样可以提高他被优先加载的机率,但是他也未必就第一个加载;所以要实现控制「操作执行顺序」,就得用设置操作的依赖关系的方式
118
119     typedef enum : NSInteger {
120         NSOperationQueuePriorityVeryLow = -8,
121         NSOperationQueuePriorityLow = -4,
122         NSOperationQueuePriorityNormal = 0,
123         NSOperationQueuePriorityHigh = 4,
124         NSOperationQueuePriorityVeryHigh = 8
125     } NSOperationQueuePriority;
126      */
127 }
128
129 @end 

SecondSampleViewController.xib

 1 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 2 <document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14E46" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES">
 3     <dependencies>
 4         <deployment identifier="iOS"/>
 5         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
 6     </dependencies>
 7     <objects>
 8         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File‘s Owner" customClass="SecondSampleViewController">
 9             <connections>
10                 <outlet property="btnLoadImage" destination="F5h-ZI-gGL" id="I40-e2-bAa"/>
11                 <outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
12             </connections>
13         </placeholder>
14         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
15         <view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
16             <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
17             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
18             <subviews>
19                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="F5h-ZI-gGL">
20                     <rect key="frame" x="230" y="530" width="140" height="50"/>
21                     <constraints>
22                         <constraint firstAttribute="height" constant="50" id="HWd-Xc-Wk7"/>
23                         <constraint firstAttribute="width" constant="140" id="vrH-qE-PNK"/>
24                     </constraints>
25                     <state key="normal" title="加载网络图片">
26                         <color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
27                     </state>
28                     <connections>
29                         <action selector="loadImage:" destination="-1" eventType="touchUpInside" id="Hgw-q8-lHy"/>
30                     </connections>
31                 </button>
32             </subviews>
33             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
34             <constraints>
35                 <constraint firstAttribute="bottom" secondItem="F5h-ZI-gGL" secondAttribute="bottom" constant="20" id="jPY-fY-9XJ"/>
36                 <constraint firstAttribute="centerX" secondItem="F5h-ZI-gGL" secondAttribute="centerX" id="rH1-sV-pST"/>
37             </constraints>
38         </view>
39     </objects>
40 </document> 

AppDelegate.h

1 #import <UIKit/UIKit.h>
2
3 @interface AppDelegate : UIResponder <UIApplicationDelegate>
4
5 @property (strong, nonatomic) UIWindow *window;
6 @property (strong, nonatomic) UINavigationController *navigationController;
7
8 @end 

AppDelegate.m

 1 #import "AppDelegate.h"
 2 #import "ViewController.h"
 3
 4 @interface AppDelegate ()
 5
 6 @end
 7
 8 @implementation AppDelegate
 9
10
11 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
12     _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
13     ViewController *viewController = [[ViewController alloc] initWithSampleNameArray:@[@"请求单张网络图片(解决线程阻塞)", @"请求多张网络图片(多个线程并发)"]];
14     _navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
15     _window.rootViewController = _navigationController;
16     //[_window addSubview:_navigationController.view]; //当_window.rootViewController关联时,这一句可有可无
17     [_window makeKeyAndVisible];
18     return YES;
19 }
20
21 - (void)applicationWillResignActive:(UIApplication *)application {
22 }
23
24 - (void)applicationDidEnterBackground:(UIApplication *)application {
25 }
26
27 - (void)applicationWillEnterForeground:(UIApplication *)application {
28 }
29
30 - (void)applicationDidBecomeActive:(UIApplication *)application {
31 }
32
33 - (void)applicationWillTerminate:(UIApplication *)application {
34 }
35
36 @end 

输出结果:

 1 2015-08-28 00:26:36.878 NSOperationDemo[4228:48976] 代码块
 2 2015-08-28 00:26:36.878 NSOperationDemo[4228:48977] 代码块
 3 2015-08-28 00:26:37.366 NSOperationDemo[4228:48976] 所有代码块操作执行完毕后(无论已取消还是已完成),做一些事情,只执行一次
 4
 5 2015-08-28 00:26:42.505 NSOperationDemo[4228:48860] Current thread:<NSThread: 0x7fbd1bd335b0>{number = 3, name = (null)}
 6 2015-08-28 00:26:42.506 NSOperationDemo[4228:48978] Current thread:<NSThread: 0x7fbd1be0ad90>{number = 4, name = (null)}
 7 2015-08-28 00:26:42.507 NSOperationDemo[4228:48990] Current thread:<NSThread: 0x7fbd1e047390>{number = 5, name = (null)}
 8 2015-08-28 00:26:42.507 NSOperationDemo[4228:48990] Current thread:<NSThread: 0x7fbd1e047390>{number = 5, name = (null)}
 9 2015-08-28 00:26:42.507 NSOperationDemo[4228:48978] Current thread:<NSThread: 0x7fbd1be0ad90>{number = 4, name = (null)}
10 2015-08-28 00:26:42.507 NSOperationDemo[4228:49025] Current thread:<NSThread: 0x7fbd1be07c70>{number = 6, name = (null)}
11 2015-08-28 00:26:42.508 NSOperationDemo[4228:48978] Current thread:<NSThread: 0x7fbd1be0ad90>{number = 4, name = (null)}
12 2015-08-28 00:26:42.508 NSOperationDemo[4228:49025] Current thread:<NSThread: 0x7fbd1be07c70>{number = 6, name = (null)}
13 2015-08-28 00:26:42.508 NSOperationDemo[4228:48978] Current thread:<NSThread: 0x7fbd1be0ad90>{number = 4, name = (null)}
14 2015-08-28 00:26:42.508 NSOperationDemo[4228:48990] Current thread:<NSThread: 0x7fbd1e047390>{number = 5, name = (null)}
15 2015-08-28 00:26:42.508 NSOperationDemo[4228:48976] Current thread:<NSThread: 0x7fbd1e0335f0>{number = 7, name = (null)}
16 2015-08-28 00:26:42.508 NSOperationDemo[4228:48978] Current thread:<NSThread: 0x7fbd1be0ad90>{number = 4, name = (null)}
时间: 2024-10-26 09:58:04

多线程开发之二 NSOperation的相关文章

iOS多线程开发(二)---线程管理

线程管理 线程管理包括创建,配置,退出三部分.主要包括创建线程的成本,线程创建,线程属性配置,线程主体入口函数编写,线程中断等 一,线程创建成本 1,为辅助线程分配的堆栈空间大小,便于系统和进程管理,以及为函数参数和局部变量分配空间 A,内核数据结构(kernel data structures)---大约1KB,This memory is used to store the thread data structures and attributes, much of which is all

多线程开发(二)-Thread、 Looper与Handler关系解密

第3节 Handler 多个线程之间除了有"执行的同步"关系,还有"数据的共享"关系,以及"功能的委托"关系. 例如之前提到的视频信息显示到列表上, 委托数据查询功能:主线程启动一个工作线程thread-查询视频信息: 委托数据的界面更新功能:工作线程查询完成后,因为不能够修改界面元素,所以必须将结果通知到主线程,委托主线程将结果的结果显示到界面上. 为此,Android SDK提供了Handler帮助各个不同的线程之间传递数据或委托功能处理.

iOS多线程开发--NSThread NSOperation GCD

多线程 当用户播放音频.下载资源.进行图像处理时往往希望做这些事情的时候其他操作不会被中 断或者希望这些操作过程中更加顺畅.在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验.早在单核处理器时期 就有多线程,这个时候多线程更多的用于解决线程阻塞造成的用户等待(通常是操作完UI后用户不再干涉,其他线程在等待队列中,CPU一旦空闲就继续执行, 不影响用户其他UI操作),其处理能力并没有明显的变化.如今无论是移动操作系统还是PC.服务器都是多核处理器,于是“并行

iOS多线程开发——GCD的使用与多线程开发浅析(二)

对于iOS多线程开发,我们时刻处于学习之中,在看书中,看文档中,项目开发中,都可以去提高自己.最近刚看完了<Objective-C高级编程 iOS与OS X多线程和内存管理>这本书后,对多线程有了更为深入的理解,故在此做一个总结与记录.这本书我已经上传至网盘  https://pan.baidu.com/s/1c2fX3EC ,这本书是iOS开发者必读的书之一,写得很不错,欢迎大家下载阅读.书的封面如下,故也称狮子书: . (1)多线程会遇到的问题 . 多线程会出现什么问题呢?当多个线程对同一

多线程开发之三 GCD

NSThread.NSOperation.GCD 总结: 无论使用哪种方法进行多线程开发,每个线程启动后并不一定立即执行相应的操作,具体什么时候由系统调度(CPU 空闲时就会执行) 更新 UI 应该在主线程(UI 线程)中进行,并且推荐使用同步调用,常用的方法如下: - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait; - (void)performSelec

.NET基础拾遗(5)多线程开发基础

Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 一.多线程编程的基本概念 下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要.我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能够在操作系统层面理解多线程的运行方式. 1.1 操作系统层面的进程和线程 (1)进程 进程代表了操作系统上运行着的一个应用程序.进程拥有自己的程序块

为什么要多线程开发

一.单线程和多线程概述. 单线程在程序执行时,所走的程序路径按照连续顺序排下来,前面的必须处理好,后面的才会执行. 单线程较多线程来说,系统稳定.扩展性极强.软件丰富.多用于点对点的服务.很多软件都有CPU单核单线程能力测试(single thread).我们都知道,多核多线程能力代表着整机性能的最高表现,而单核单线程能力则是可以体现在某些低功耗运行设定下的实际性能表现.用户需要知道自己的设备性能极限在哪里,也需要知道自己能日常够用到的性能大概有多少. 在固有的观念中,CPU核心数量的增多会被认

Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一.事件派发线程的前世今生 事件(Event)派发(Dispatch)线程(Thread)简写为EDT,也就是各个首字母的简写.在一些书或者博客里边也将其译为事件分发线程.事件调度线程.巴拉巴拉,总之,知道这些名字就行.笔者认为这里翻译成派发更准确点. 熟悉Swing和awt编程的小伙伴对事件派发线程

Java多线程开发系列之一:走进多线程

对编程语言的基础知识:分支.选择.循环.面向对象等基本概念后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介绍 多线程开发的概念.使用.线程状态.同步.线程池.希望与大家共勉. 在第一部分,也就是本节我们先介绍下 什么是多线程程序.线程和进程又是什么,以及为什么要搞多线程. (一)什么是多线程程序 多线程听上去是非常专业的概念,其实非常简单,我们在日常生活中,经常的接触到多线程. 比如 (1)在工厂,工人努力