• 多线程开发之二 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)}
  • 相关阅读:
    jQuery对象和DOM对象的互转
    ASP.NET MVC单元测试Controller时添加上下文的方式
    基于Mongodb进行分布式数据存储【转】
    .NET平台上的编译器不完全列表
    实现自己的O/R Mapping组件高效缓存的思考
    .NET的动态语言
    C++类成员和数据成员初始化总结
    ACE Singleton
    Wiresshark
    C++
  • 原文地址:https://www.cnblogs.com/huangjianwu/p/4765215.html
Copyright © 2020-2023  润新知