多线程开发之二 NSOperation
效果如下:
ViewController.h
1 #import <UIKit/UIKit.h> 2 3 @interface ViewController : UITableViewController 4 @property (copy, 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:@"PictureNo@2x" 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:@"PictureNo@2x" 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)}