Objective-C——了解Block(一)

了解Block(一)——初谈block


———- android培训java培训、期待与您交流! ———-


引入——一个简单的block

我们先从一个简单的block开始,先看代码:


#import <Foundation/Foundation.h>

BOOL (^isZeroSum)(int, int ,int *) = ^(int score1, int score2, int *sum)
{
    *sum = score1 +score2;
    if(*sum == 0){
        return NO;
    }
    return YES;
};

int main(int argc, const char* argv[])
{
    @autoreleasepool{
        int score1 = 0, score2 = 0, sum = 0;
        score1 = 20;
        score2 = 10;
        BOOL flag = isZeroSum (score1, score2, &sum);

        switch (flag){
            case 0:
                NSLog(@"请努力学习!");
                break;
            default:
                NSLog(@"您的分数是: %d", sum);
        }
    }
    return 0;
}

Output:     您的分数是: 30

1.简单介绍下这个block的结构,如下图所示:

这里写图片描述

2.BOOL

在这里我给这个block整了个BOOL类型的返回值,是临时想起来OC中关于BOOL的一个小坑这里简单作为题外话插讲一下:

  • 类型的定义:

    typedef signed char BOOL;

  • 取值的定义:

    #define YES (BOOL)1
    #define NO  (BOOL)0

也就是说我们不能直接return (*sum = score1 +score2);这样我们永远也不能像C语言一样的到YES的答案因为从上面去指定义可以看出来这里只有在值为1的时候才是YES,而C中只要是非0值就能让条件成立。

3.局部变量(自动变量)的使用

好我们回到正题:
从上面这段简单的代码中看到了block中一个参数是指针类型的,这说明了我们要想改变main函数内block外部的自动变量sum的值可以通过传递变量指针的形式来做,其实能够改变函数内自动变量的值还可以通过使用__block关键字来修饰自动变量的方法。但是为什么要这么做呢?我们下面来分析一下:

clang

我们先来阅读下经过clang编译器转换后的代码,找出重要信息(因为比较大生成的.cpp文件有2.82M)
在mac控制台键入:clang -rewrite-objc .m文件的URL

#ifndef __OBJC2__
#define __OBJC2__
#endif
struct objc_selector; struct objc_class;
struct __rw_objc_super { 
    struct objc_object *object; 
    struct objc_object *superClass; 
    __rw_objc_super(struct objc_object *o, struct objc_object *s) : object(o), superClass(s) {} 
};
#ifndef _REWRITER_typedef_Protocol
typedef struct objc_object Protocol;
#define _REWRITER_typedef_Protocol
#endif
#define __OBJC_RW_DLLIMPORT extern
__OBJC_RW_DLLIMPORT void objc_msgSend(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSendSuper_stret(void);
__OBJC_RW_DLLIMPORT void objc_msgSend_fpret(void);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getClass(const char *);
__OBJC_RW_DLLIMPORT struct objc_class *class_getSuperclass(struct objc_class *);
__OBJC_RW_DLLIMPORT struct objc_class *objc_getMetaClass(const char *);
__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);
__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);
__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);
__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);
#ifdef _WIN64
typedef unsigned long long  _WIN_NSUInteger;
#else
typedef unsigned int _WIN_NSUInteger;
#endif
#ifndef __FASTENUMERATIONSTATE
struct __objcFastEnumerationState {
    unsigned long state;
    void **itemsPtr;
    unsigned long *mutationsPtr;
    unsigned long extra[5];
};
__OBJC_RW_DLLIMPORT void objc_enumerationMutation(struct objc_object *);
#define __FASTENUMERATIONSTATE
#endif
#ifndef __NSCONSTANTSTRINGIMPL
struct __NSConstantStringImpl {
  int *isa;
  int flags;
  char *str;
  long length;
};
#ifdef CF_EXPORT_CONSTANT_STRING
extern "C" __declspec(dllexport) int __CFConstantStringClassReference[];
#else
__OBJC_RW_DLLIMPORT int __CFConstantStringClassReference[];
#endif
#define __NSCONSTANTSTRINGIMPL
#endif
#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};
// Runtime copy/destroy helper functions (from Block_private.h)
#ifdef __OBJC_EXPORT_BLOCKS
extern "C" __declspec(dllexport) void _Block_object_assign(void *, const void *, const int);
extern "C" __declspec(dllexport) void _Block_object_dispose(const void *, const int);
extern "C" __declspec(dllexport) void *_NSConcreteGlobalBlock[32];
extern "C" __declspec(dllexport) void *_NSConcreteStackBlock[32];
#else
__OBJC_RW_DLLIMPORT void _Block_object_assign(void *, const void *, const int);
__OBJC_RW_DLLIMPORT void _Block_object_dispose(const void *, const int);
__OBJC_RW_DLLIMPORT void *_NSConcreteGlobalBlock[32];
__OBJC_RW_DLLIMPORT void *_NSConcreteStackBlock[32];
#endif
#endif
#define __block
#define __weak

#include <stdarg.h>
struct __NSContainer_literal {
  void * *arr;
  __NSContainer_literal (unsigned int count, ...) {
    va_list marker;
    va_start(marker, count);
    arr = new void *[count];
    for (unsigned i = 0; i < count; i++)
      arr[i] = va_arg(marker, void *);
    va_end( marker );
  };
  ~__NSContainer_literal() {
    delete[] arr;
  }
};
extern "C" __declspec(dllimport) void * objc_autoreleasePoolPush(void);
extern "C" __declspec(dllimport) void objc_autoreleasePoolPop(void *);

struct __AtAutoreleasePool {
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)
static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s5_3xp65sgx78v3_ny_tzg28r080000gn_T_tmp_3c9a21_mi_0 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"\350\257\267\345\212\252\345\212\233\345\255\246\344\271\240!",16};
static __NSConstantStringImpl __NSConstantStringImpl__var_folders_s5_3xp65sgx78v3_ny_tzg28r080000gn_T_tmp_3c9a21_mi_1 __attribute__ ((section ("__DATA, __cfstring"))) = {__CFConstantStringClassReference,0x000007c8,"\346\202\250\347\232\204\345\210\206\346\225\260\346\230\257: %d",19};


下面这是我们写的代码的翻译
struct __isZeroSum_block_impl_0 {
  struct __block_impl impl;
  struct __isZeroSum_block_desc_0* Desc;
  __isZeroSum_block_impl_0(void *fp, struct __isZeroSum_block_desc_0 *desc, int flags=0) {
    impl.isa = &_NSConcreteGlobalBlock;
    impl.Flags = flags;
    impl.FuncPtr = fp;
    Desc = desc;
  }
};
static BOOL __isZeroSum_block_func_0(struct __isZeroSum_block_impl_0 *__cself, int score1, int score2, int *sum) {

    *sum = score1 +score2;
    if(*sum == 0){
        return ((bool)0);
    }
    return ((bool)1);
}

static struct __isZeroSum_block_desc_0 {
  size_t reserved;
  size_t Block_size;
} __isZeroSum_block_desc_0_DATA = { 0, sizeof(struct __isZeroSum_block_impl_0)};
static __isZeroSum_block_impl_0 __global_isZeroSum_block_impl_0((void *)__isZeroSum_block_func_0, &__isZeroSum_block_desc_0_DATA);
BOOL (*isZeroSum)(int, int ,int *) = (BOOL (*)(int, int, int *))&__global_isZeroSum_block_impl_0;

int main(int argc, const char* argv[])
{
    /* @autoreleasepool */{ __AtAutoreleasePool __autoreleasepool; 
        int score1 = 0, score2 = 0, sum = 0;
        score1 = 20;
        score2 = 10;
        BOOL flag = ((BOOL (*)(__block_impl *, int, int, int *))((__block_impl *)isZeroSum)->FuncPtr)((__block_impl *)isZeroSum, score1, score2, &sum);

        switch (flag){
            case 0:
                NSLog((NSString *)&__NSConstantStringImpl__var_folders_s5_3xp65sgx78v3_ny_tzg28r080000gn_T_tmp_3c9a21_mi_0);
                break;
            default:
                NSLog((NSString *)&__NSConstantStringImpl__var_folders_s5_3xp65sgx78v3_ny_tzg28r080000gn_T_tmp_3c9a21_mi_1, sum);
        }


    }
    return 0;
}
static struct IMAGE_INFO { unsigned version; unsigned flag; } _OBJC_IMAGE_INFO = { 0, 2 };

从上面的代码我们可以看到有下面这么一段

BOOL flag = ((BOOL ()(__block_impl , int, int, int ))((__block_impl )isZeroSum)->FuncPtr)((__block_impl *)isZeroSum, score1, score2, &sum);

从这我们可以看出我们score1,score2都是赋值接收的main函数的局部变量也就是相当于拿到了局部变量的副本,所以我们在这种情况下在block内部修改了score1或score2的值不会对block外部的该变量造成任何影响。我们将score2变量加上__block关键字再次用clang分析下,得到该段的代码如下:

BOOL flag = ((BOOL ()(__block_impl , int, int, int ))((__block_impl )isZeroSum)->FuncPtr)((__block_impl *)isZeroSum, score1, (score2.__forwarding ->score2), &sum);

我们不难看出score2被结构体指针所引用。也就是说在这里的score2已经是对main函数内的score2的直接使用了所以在block内部修改score2的值main函数内的score2变量也会受到影响。
这就说明被关键字__block修饰了的自动变量在作为block的Argument时会将该变量的地址传给block让其进行相关处理。


block是什么?

我们从block的声明和定义来看,这像一个什么?像一个类似结构体的语法 ,也更像是一个匿名函数。那么他到底是什么?我们来看一下官方文档怎么说的。

Block objects are a C-level syntactic and runtime feature. They allow you to compose function expressions that that can be passed to API, optionally stored, and used by multiple threads. The function expression can reference and can preserve access to local variables.

请注意Apple官方的主语用的是Block objects也就是说用意是要让block有对象一样的用途,也要有C类似的语法结构。
我们再看一下我们通过clang得到的部分代码

#ifndef BLOCK_IMPL
#define BLOCK_IMPL
struct __block_impl {
  void *isa;
  int Flags;
  int Reserved;
  void *FuncPtr;
};

我们看到了真正的万能指针void*以及我们在oc中天天接触的is a.那么答案就不言而喻了。

PS:(水平有限,下回再写高级部分)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值