转载

Block学习笔记

编译器和运行时让block中引用的所有变量都被保存下来,以备在block的所有副本的生命周期中使用。

- (void)block1
{
    int (^myTest)(int) = ^(int num){
        return num * num;
    };
    NSLog(@"double: %d",myTest(9));
}

2.在block中改变的外部变量,需要用 __block 声明

- (void)block2
{
    NSArray *stringsArray = @[ @"string 1",
                               @"String 21", // <-
                               @"string 12",
                               @"String 11",
                               @"Strîng 21", // <-
                               @"Striñg 21", // <-
                               @"String 02" ];

    NSLocale *currentLocale = [NSLocale currentLocale];
    __block NSUInteger orderedSameCount = 0;

    NSArray *diacriticInsensitiveSortArray = [stringsArray sortedArrayUsingComparator:^(id string1, id string2) {

        NSRange string1Range = NSMakeRange(0, [string1 length]);
        NSComparisonResult comparisonResult = [string1 compare:string2 options:NSDiacriticInsensitiveSearch range:string1Range locale:currentLocale];

        if (comparisonResult == NSOrderedSame) {
            orderedSameCount++;
        }
        return comparisonResult;
    }];

    NSLog(@"diacriticInsensitiveSortArray: %@", diacriticInsensitiveSortArray);
    NSLog(@"orderedSameCount: %lu", (unsigned long)orderedSameCount);
}

3.block支持不定个数的参数(variadic arguments)

- (void)block3
{
    void (^variadicParams)(NSString*, ...) = ^(NSString *format, ...) {
        id eachObject;
        va_list argumentList;   // va_list是指向变量列表的指针
        if (format) {   // 第一个参数并不是变量列表中的一个
            NSMutableArray *tmpArray = [NSMutableArray arrayWithObject:format];
            va_start(argumentList, format); // 初始化va_list,并让它指向传入的参数(format)后面紧跟的第一个参数
            while ((eachObject = va_arg(argumentList, id)) != nil){  //   va_arg,取出列表中的下一个参数。必须指明参数的类型(这样va_arg才能知道该给它分配多少空间)
                [tmpArray addObject:eachObject];    // 不会把任何nil对象添加到tmpArray中
            }
            va_end(argumentList);   // 释放va_list这个数据结构所持有的任何内存
            NSLog(@"variadic params: %@",tmpArray);
        }
    };

    variadicParams(@"11",@"22",@"333",@"666",nil);  //   Calios:这里最后一个参数必须传nil,args必须有最后一个结尾,否则是无法判断的。But,why?
}

4.几种类型的变量与block的交互

NSInteger CounterGlobal;    //   Calios:It throws out error for not finding CounterGlobal if extern is added. But, why?
static NSInteger CounterStatic;

- (void)block4
{
    NSInteger localCounter = 42;
    __block char localCharacter;

    void (^aBlock)(void) = ^(void) {
        ++CounterGlobal;
        ++CounterStatic;
        CounterGlobal = localCounter; // localCounter fixed at block creation
        localCharacter = 'a'; // sets localCharacter in enclosing scope
    };

    ++localCounter; // unseen by the block
    localCharacter = 'b';

    aBlock(); // execute the block
    // localCharacter now 'a'
}

5.当block被复制的时候,它会对block中使用的对象变量产生强引用。

如果你在一个方法的实现中使用了block:

  • 如果你使用了实例变量的引用,那么就对 self 产生了强引用;

    • 如果你使用了实例变量的值,那么就对 该变量 产生了强引用。

      • (void)block5

        {

        void (^doSomethingWithObject)(id) = ^(id var){

        NSLog(@”do something: %@”,var);

        };

        dispatch_queue_t queue = dispatch_queue_create(“com.calios.BlockSample.someQueue”, DISPATCH_QUEUE_SERIAL);

        dispatch_async(queue, ^{ // dispatch_async()是将block拷贝到指定的queue中,而复制操作(Block_copy())会将block移动到堆上。

        // instanceVariable is used by reference, a strong reference is made to self

        doSomethingWithObject(instanceVariable);

        });

id localVariable = instanceVariable;
dispatch/_async(queue, ^{
    /*
     localVariable is used by value, a strong reference is made to localVariable
     (and not to self).
     */
    doSomethingWithObject(localVariable);
});
    }

6.应该避免的做法

block字面量(即^{ … })是代表这个block的局部栈数据结构的地址。因此,局部栈数据结构的作用于就是仅限于大括号中的语句,所以你应 避免 向下面这样使用block。

- (void)block6
{
    dontDoThis();
    dontDoThisEither();
}

void dontDoThis() {
    void (^blockArray[3])(void);  // an array of 3 block references

    for (int i = 0; i < 3; ++i) {
        blockArray[i] = ^{ printf("hello, %d/n", i); };
        // WRONG: The block literal scope is the "for" loop.
    }
}

void dontDoThisEither() {
    void (^block)(void);

    int i = arc4random() % 1024;
    if (i > 1000) {
        block = ^{ printf("got i at: %d/n", i); };
        // WRONG: The block literal scope is the "then" clause.
    }
    // ...
}

Ref:

  • https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Blocks/Articles/00_Introduction.html
原文  http://www.calios.gq/2017/01/10/Block学习笔记/
正文到此结束
Loading...