美文网首页Swift 专栏
13.闭包(特殊的函数)

13.闭包(特殊的函数)

作者: IIronMan | 来源:发表于2017-05-16 17:30 被阅读24次
    • 1.闭包的介绍

      • 闭包和OC中的block非常相似
        • OC中的block是匿名的函数
        • Swift中的闭包是一个特殊的函数
        • block和闭包都经常用于回调
      • 注意:闭包和block一样,第一次使用时可能不习惯它的语法,可以先按照使用简单的闭包,随着学习的深入,慢慢掌握其灵活的运用方法.
    • 2.闭包的使用

      • 1.先回顾一下block的使用

        @property(nonatomic,strong) void(^myblock)();
        // block 的格式: 返回值类型(^block名称) (参数列表)
        self.myblock = ^(){
        
                NSLog(@"block的打印");
        
         };
        self.myblock();
        
      • 2.闭包的基本介绍
        /*
        * 闭包和oc中的block非常相似
        * oc中的block类似于匿名函数
        * 闭包是用来定义函数
        * 作用: block 是用于保存一段代码,在需要的时候执行
        * 闭包也是用于保存一段代码,在需要的时候执行
        * 做一个耗时的操作
        */

        /*
         * 闭包的基本格式:
           in的含义是用来区分形参返回值和要执行的代码
         *  {
              (形参列表) -> (返回值)
               in
               需要执行的代码
            }
         *
         */
          loadData {
            
            print("回调")
        }
        
        func loadData(request:()->()){
        
            print("执行耗时操作")
            request()
        
        }
        
    • 3.闭包的几种格式

      • 1.将闭包通过实参传递给函数

        loadData (request: { 
           
            print("回调")
         })
         func loadData(request:()->()){
        
            print("执行耗时操作")
            request()
        
         }
        
    • 2.如果闭包是函数的最后一个参数,那么闭包可以写在函数()的后面
      loadData() {

            print("回调2")
           
       }
       func loadData(request:()->()){
      
           print("执行耗时操作")
           request()
      
       }
      
    • 3.如果函数只接受一个参数,并且这个参数是闭包,那么()可以省略
      loadData {

           print("回调2")
          
      }
      
      func loadData(request:()->()){
      
           print("执行耗时操作")
           request()
      
      }
      
    • 4.闭包的返回值和参数

    /*
     *  两个闭包  创建一个 UIscrollview 上添加button
     *
     *
     */
    let sc1 = createScrollview(buttonCount: { () -> Int in
        
        return 15
    }) { (index) -> UIView in
        
        let width1 = 80
        let button = UIButton()
        button.backgroundColor = UIColor.red
        button.frame = CGRect(x:index*width1,y:10,width:width1,height:80)
        button.setTitle("标题\(index)", for: UIControlState(rawValue: 0))
        return button
        
        }
        
    view.addSubview(sc1)
        
        /*
         * 要求定义一个方法来创建UIScrollView,
         * 1.并且上面有多个按钮,必须通过闭包来告诉该方法
         * 2.并且如何创建按钮也需要闭包来创建
         */
       
        // 5.将scrollview添加到控制器的view上
        // 特点: 没有写self
        // swift推荐:能不写self就不写self
    
        func createScrollview(buttonCount:()->Int,buttonIndex1: (_ num:Int)->UIView) -> UIScrollView {
        
        // 数组的数量
        let count = buttonCount()
        
        // 1.创建scrollview
        let sc = UIScrollView(frame: CGRect(x:0,y:64,width:414,height:100))
        sc.backgroundColor = UIColor.blue
        view.addSubview(sc)
        
        // 2.在scrollview上放置button
        
        for i in 0..<count {
            
            /*
            let button = UIButton()
            button.backgroundColor = UIColor.red
            button.frame = CGRect(x:i*width1,y:10,width:width1,height:80)
            button.setTitle("标题\(i)", for: UIControlState(rawValue: 0))
            sc.addSubview(button)
            */
            
            let button = buttonIndex1(i)
            sc.contentSize = CGSize(width:CGFloat(count) * button.bounds.width,height:100)
            sc.addSubview(button)
            
        }
        
        return sc
    }
    
    • 5.循环引用

       import UIKit
      
      class ViewController: UIViewController {
      
       /*
        * 在swift中,如果在某个类中定义一个属性,那么这个属性必须要初始化,否则就会报错
        * 如果暂时不想初始化,那么可以在后面写上一个 ? 也就是可选类型
        */
      
        // 注意:这个是错误的写法,当前写法代表闭包的返回值可以是nil
        //var finsh: ()->()?
        // 下面是正确的写法
        var finsh: (()->())?
       
        override func viewDidLoad() {
        super.viewDidLoad()
       
        weak var weakSelf = self
        loadata { 
            
            print("回调")
            // 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
            // 所以以后看到self基本上都是和闭包有关系
            weakSelf!.view.backgroundColor = UIColor.brown
              
            }
        
        }
      
        func loadata(finsh:()->())  {
        
        print("执行耗时操作")
        finsh()
        
        }
      
        override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
       }
      
      }
      

    **循环引用解决:以上面的为例

    方式一:
    - 使用weak,对当前控制器使用弱引用
    - 但是因为self可能有值也可能没有值,因此weakSelf是一个可选类型,在真正使用时可以对其强制解包(该处强制解包没有问题,因为控制器一定存在,否则无法调用所在函数)
    weak var weakSelf = self
    loadata {

           print("回调")
           // 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
           // 所以以后看到self基本上都是和闭包有关系
            weakSelf!.view.backgroundColor = UIColor.brown
    
            }
          }
    

    方式二:
    - 和方案一类型,只是书写方式更加简单
    - 可以写在闭包中,并且在闭包中用到的self都是弱引用
    loadata { [weak self] () -> () in

                print("回调")
                // 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
                // 所以以后看到self基本上都是和闭包有关系
                self!.view.backgroundColor = UIColor.brown
    
                }
            }
    
    方式三:
     -  使用关键字unowned
     - 从行为上来说 unowned 更像OC中的 unsafe_unretained
     - unowned 表示:即使它原来引用的对象被释放了,仍然会保持对被已经释放了的对象的一个 "无效的" 引用,它不能是 Optional 值,也不会被指向 nil
    
            loadata { [unowned self] () -> () in
    
                print("回调")
                // 在swift开发中,能不写self就不写self,但是在闭包中必须写上self
                // 所以以后看到self基本上都是和闭包有关系
                self.view.backgroundColor = UIColor.brown
    
              }
            }

    相关文章

      网友评论

        本文标题:13.闭包(特殊的函数)

        本文链接:https://www.haomeiwen.com/subject/trvhxxtx.html