Object-c Block的使用及说明

Object-c 中的block就好像一段C函数般,由函数名,有返回值,有参数,由函数体等

1.简单的block

  

1 ^(int A ,int B)
2     {
3         int C=A*B;
4         return C;
5     };

上述代码表示block有两个整形参数A和B.在block体中进行A和B的相乘,将结果作为block的返回值返回出去。

2.将block作为参数的API

   在程序开发时,当需要一个NSArray对象的所有元素进行遍历时,除了for循环,开发者可以使用block进行遍历,代码如下:

1  NSArray *arrChar=[@"A/B/C/D/E/F" componentsSeparatedByString:@"/"];
2     //遍历元素
3     [arrChar enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
4         NSLog(@"\nindex:[%d], value:[%@]",idx,obj);
5         if(idx == 4)
6         {
7             *stop=YES;
8         }
9     }];

这段代码运行后,在控制台上留下了如下日志:

index:[0], value:[A]
index:[1], value:[B];
index:[2], value:[C];
index:[3], value:[D];
index:[4], value:[E];

 这里,NSArray对象所使用的API主要是一个对自己元素的遍历功能,enumerateObjectsUsingBlock方法的参数需要是一个block对象,在NSArray的帮助文档中,我们找到了enumerateObjectsUsingBlock的声明,内容如下:

-(void)enumerateObjectsUsingBlock:(void)(^(id obj,NSInterger idx,BOOL *stop))block

所传入的3个参数中,前两个是表明当前元素指针和序号的输入参数,开发者直接拿来使用即可。最后一个参数讲一个布尔类型的指针传递进来,显然是属于一个典型的输入参数。这个参数让开发者可以灵活的控制遍历的继续执行是否。

3.block的声明

  block在声明时,需要遵循如下所示的格式结构。

  

<返回值类型> + (^<block名字>) + (<参数类型1>, <参数类型2>...)

 根据enumerateObjectsUsingBlock的结构,我们声明的block变量对象如下:

void (^arrayEnumerateBlock)(id,NSUInteger,BOOL *);

 对于声明完的block变量,可以直接进行初始化,也可以进行赋值。block的初始化格式如下:

void (^arrayEnumerateBlock)(id,NSUInteger,BOOL *)=^(id anObject, NSUInteger index, BOOL *isStop)
{
     NSLog(@"\nindex:[%d], value:[%@]", index, anObject);

     //序号4, 则停止遍历
     if(index == 4)
     {
          *isStop=YES;
     }
};

上述代码中对于变量的初始化,开发者同样需要加上“^”符号表明这是一个block类型。不过block的返回值和block名不用写明,block名作为声明的一部分已经在声明时写明,至于返回值,只需要在block体中严格遵守返回类型即可。

4.block 的 typedef

  在平时开发中,我们习惯于使用typedef定义属于自己框架的东西,本质上其实是为了类型使用更加统一。

  而block由于有着相对复杂的声明方式,不如可以考虑将block的格式进行typedef,之后所有需要遵循这个block格式的对象声明再也不需要考虑格式的撰写,并且由于block有着函数指针般的接口协议特征,使用typedef定义过的block格式,当作为接口提供外部调用时,调用者可以明确具体需要给与的参数格式。

   同样是enumerateObjectsUsingBlock所用的那个block格式,typedef定义示例如下

  

typedef void (^ArrayEnumerateBlockType)(id ,NSUInteger, BOOL *);

虽然typedef后接着的格式和前一小节中block声明格式相当相似,不过typedef所书写的内容是类型名字,而block声明时所书写的是变量对象的名字。所以在这里,我们特意以ArrayEnumerateBlockType定义类型名和之前的arrayEnumerateBlock变量类型名加以区分。

一旦有了typedef过得block类型后,到哪里都能够简单的使用这个block了,初始化代码如下:

ArrayEnumerateBlockType aEnumerateBlock=^(id aObject, NSUInteger index, BOOL *isStop)
{
     //跟前面一样
}

 

5.block体的外部变量使用的奇怪之处

  首先,让我们来看看以下代码。

 1     NSUInteger result   = 0;
 2     NSUInteger changeValue=0;
 3     //block变量声明
 4     NSUInteger (^testReturnValueBlock)(NSUInteger, NSUInteger) = ^(NSUInteger param1, NSUInteger param2)
 5     {
 6         return param1+param2+changeValue;
 7     };
 8     
 9     result=testReturnValueBlock(1,2);
10     NSLog(@"1.[%d]",result);
11     
12     changeValue++;
13     result=testReturnValueBlock(1,2);
14     NSLog(@"2.[%d]",result);

执行结果却是

1.[3]
2.[3]

 是不是觉得相当奇怪,我明明在第一次日志打印后对changeValue变量执行了++操作,其实打印的结果并没有错,我们需要更深入的了解block内部机制才能够看懂这其中的奥妙。

在block体中,我们不仅能够访问到block声明的传入参数,也能够正常访问到block以外的变量,不过,对于block以外的变量来说,如果把它放在block内进行访问也罢赋值也罢,一旦进入了block体中,基本类型变量会被block进行一次copy后以一个临时变量存放在block体中,而指针变量会被block进行一次retain后也以一个临时变量存放起来,无论是基本数据类型还是指针,被block使用了,就表明他的生命周期除了自己本身所在的作用域,又多了一个block体的作用域,也就是说:

   (1)基本数据类型在block中的地址已经发生变化,所以block体外对于此数据类型的值修改对于体内的值毫无影响。

   (2)block所copy或者retain的变量,一旦block结束,也就一起跟着被释放和销毁了。

   (3)所谓的block会进行retain的指针类型,也包含Object-c中的所有对象。

6.克服外部变量的魔咒

   (1)可以把外部变量修改成  static NSUInteger changeVaue=0;

          static 关键字意味着changeValue的地址不再被我们放置于栈中,不过也并不在堆中,而是放在全局数据区,拥有一个永远不会改变的地址。

   (2)也可以在外部变量前加上 __block   如:  __block NSUInteger changeValue=0;

          当一个变量被__block所修饰时,block体中就会知道,即使使用到这个外部变量,也坚决不会去进行retain或者copy,这样就能够保证内外统一了

转载于:https://www.cnblogs.com/haibosoft/p/3655881.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS中使用公钥字符串进行RSA加密的步骤如下: 1. 将公钥字符串转换为NSData类型。 ``` NSString *publicKeyString = @"-----BEGIN PUBLIC KEY-----\n...公钥字符串...\n-----END PUBLIC KEY-----"; NSData *publicKeyData = [publicKeyString dataUsingEncoding:NSUTF8StringEncoding]; ``` 2. 创建SecKey对象。 ``` NSMutableDictionary *publicKeyAttributes = [[NSMutableDictionary alloc] init]; [publicKeyAttributes setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; [publicKeyAttributes setObject:@(2048) forKey:(__bridge id)kSecAttrKeySizeInBits]; [publicKeyAttributes setObject:publicKeyData forKey:(__bridge id)kSecValueData]; [publicKeyAttributes setObject:(__bridge id)kSecAttrKeyClassPublic forKey:(__bridge id)kSecAttrKeyClass]; SecKeyRef publicKey; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKeyAttributes, (CFTypeRef *)&publicKey); ``` 3. 使用SecKey对象进行加密。 ``` NSData *plainData = [@"要加密的数据" dataUsingEncoding:NSUTF8StringEncoding]; size_t cipherBufferSize = SecKeyGetBlockSize(publicKey); uint8_t *cipherBuffer = malloc(cipherBufferSize); memset(cipherBuffer, 0, cipherBufferSize); OSStatus status = SecKeyEncrypt(publicKey, kSecPaddingPKCS1, [plainData bytes], [plainData length], cipherBuffer, &cipherBufferSize); NSData *encryptedData = [NSData dataWithBytesNoCopy:cipherBuffer length:cipherBufferSize]; ``` 4. 释放SecKey对象。 ``` CFRelease(publicKey); ``` 注意:在iOS中使用公钥加密时,需要使用PKCS#1填充模式(kSecPaddingPKCS1)。另外,如果公钥字符串中的换行符不是`\n`,需要将其替换为`\n`。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值