Swift 闭包 与 OC block区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift 闭包 与 OC block区别相关的知识,希望对你有一定的参考价值。

参考技术A 点击button输出全部为4,这和OC不一样。在OC Block中对局部自动变量的捕获方式默认为值捕获,而在swift中默认为指针捕获。若要将闭包捕获方式改为值捕获,参考如下:

输出结果为0,1,2,3,4。

Swift3.0 函数闭包与OC Block

刚接触Swift,如有不对,欢迎指正

  • Swift中定义一个基本函数
//定义一个函数,接收一个字符串,返回一个String类型的值
func test(name:String) -> String {

        return ("输出了\\(name)")
    }
//通用形式
 func name(parameters) -> return type {
        function body
    }

 

  • Swift 中基本的闭包函数与OC中Block的相似点
  • 带参闭包
    //OC中Block是这样
    void (^test) (NSString *)=^(NSString *name){
    
            NSLog(@"%@",name);
    
        };
    
        test(@"测试");
    //对应到swift的带参闭包
    
    let test={(_ name:String)->() in
    
      // in 后面就是回调之后处理的函数 ,相当于是Block之后的{ }
                print(name)
    
            }
    
            test("测试")
    
    //通用形式
    { 
    (parameters) -> returnType in
       code
    }

    这里下划线 _ 的作用用来忽略外部參数名,具体可以参考这篇文章http://www.cnblogs.com/bhlsheji/p/4746072.html

     

 

  • OC中带Block参数的函数定义
-(void)loadData:(  void(^)(void) )completetion
{
    completetion();
}

 

  • Swift中带闭包参数的函数定义
func loadData(completetion: ()->()) -> () {
       completetion()
    }
//样式 func: ()->() 

 

  • 举个比较常用的例子,网络数据获取
//OC中Block传值
-(void)loadData:(  void(^)(NSArray *) )completetion
{

//这里暂时先忽略掉线程,简单处理,重点在swift闭包
    NSLog(@"耗时操作");

    sleep(2);//模拟网络请求

    NSArray *arr=@[@"1",@"2"];

    NSLog(@"主线程回调");


    completetion(arr); //返回获得的数据

}

调用:
 [self loadData:^(NSArray *callBack){

        NSLog(@"%@,%@",callBack[0],callBack[1]);

    }];

输出:
2017-03-22 18:48:45.273 tessst[3642:187462] 耗时操作
2017-03-22 18:48:47.345 tessst[3642:187462] 主线程更新
2017-03-22 18:48:47.346 tessst[3642:187462] 1,2


//swift中闭包传值  
       func loadDate(completion: @escaping (_ result : [String])->()) -> () {

//这里有一个很重要的参数 @escaping,逃逸闭包
//简单来说就是 闭包在这个函数结束前内被调用,就是非逃逸闭包,调用的地方超过了这函数的范围,叫逃逸闭包
//一般网络请求都是请求后一段时间这个闭包才执行,所以都是逃逸闭包。
// 在Swift3.0中所有的闭包都默认为非逃逸闭包,所以需要用@escaping来修饰
        DispatchQueue.global().async {

            print("耗时操作\\(Thread.current)")
            Thread.sleep(forTimeInterval: 2)
            let json=["1","2"]

            DispatchQueue.main.async {
                print("主线程更新\\(Thread.current)")

                completion(json)
//函数在执行完后俩秒,主线程才回调数据,超过了函数的范围,这里就是属于逃逸闭包,如果不用@escaping,编译器是编译不过的
            }
        }
    }

主函数调用loadDate:
 loadDate { (callBack) in
        print("\\(callBack)")
        }

输出值
耗时操作<NSThread: 0x608000069140>{number = 1, name = main}
主线程更新<NSThread: 0x608000069140>{number = 1, name = main}
1,2

 

  • 在Block中经常会有循环引用的情况,闭包中也一样,常用的解决方式有俩种
//第一种
weak var weakwelf=self
//套用oc的方式(__weak typedef(weakself)=self).
//这里要注意,不能用  let  ,因为self可能会释放指向nil,相当于是一个可变值

//调可选项发送消息的时候 用 ? 解包 不用 !

pringt("weakself ?.view") 不用" weakself!.view"
//因为强制解包一旦weakself=nil时会崩溃

//第二种,在调用时候
//[weak self]标识在{}中所有的self都是弱引用
 loadDate { [weak self] in
            print(self?.view)
        }

  • 尾随闭包

 尾随闭包是一个书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。可以使用尾随闭包来增强函数的可读性。

    func someFunctionThatTakesAClosure(closure: () -> ()) {
        // 函数体部分
    }

    // 以下是不使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure({
        // 闭包主体部分
    })

    // 以下是使用尾随闭包进行函数调用
    someFunctionThatTakesAClosure() {
        // 闭包主体部分
    }

 

 

续更...

以上是关于Swift 闭包 与 OC block区别的主要内容,如果未能解决你的问题,请参考以下文章

Swift之“闭包”的应用

swift中闭包和OC的block的对比

swift学习第十五天:闭包

Swift-- 闭包

Swift 学习- 08 -- 闭包

Swift:闭包(Closures)