Swift实现java匿名内部类的用法教程和demo下载

54 篇文章 1 订阅
1 篇文章 0 订阅

前言

最近研究RxSwift框架发现里面用到了匿名内部类的思想,今天做了一下总结,文章最后有demo下载

匿名内部类的作用

java中有匿名内部类的语法,可以做到的是,就是想要重写一个类中的方法,并且执行,但是不想重新定义一个类,因为只调用一次,或者调用多次,但是每次调用的实现过程都不同,这时候就可以使用匿名内部类

java中的匿名内部类

public class HelloWorldAnonymousClasses {

    /**
     * 包含两个方法的HelloWorld接口
     */
    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        // 1、局部类EnglishGreeting实现了HelloWorld接口
        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        // 2、匿名类实现HelloWorld接口
        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        // 3、匿名类实现HelloWorld接口
        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };

        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp = new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }
}

运行结果:
1 Hello world
2 Salut Fred
3 Hola, mundo

swift中实现匿名内部类

理想中的跟java一样的swift匿名内部类(语法编译错误)

swift中并没有匿名内部类的语法,就是 类名 变量 = new 类名() { 重写类内的内容 } 调用的时候 对象.方法名()
按照java 的做法, swift,按照执行匿名闭包的做法应该写成如下,但是这样写编译器会报错,
关于匿名闭包的用法,请参照我这篇文章:
swift的匿名闭包用法教程
let 变量 = class 类名


protocol PersonProtocol2 {
    func hello(str: String) -> ()
}
let obj = class Person2 : PersonProtocol2 { //这样编译会报错,不能定义类的时候再用()执行类创建对象,赋值给变量
    func hello(str: String) -> () {
        
    }
}()

真实的匿名内部类

做法1

通过协议,让类实现协议,并且实现协议中的方法,再建立类对象,并且执行类对象的方法,再赋值给闭包表达式,执行的时候是执行闭包表达式,如下执行的时候,执行:closure1(),这个做法是把整个执行过程包装起来,调用的是闭包变量,下面closure1和 closure2分别实现2个不同的执行过程,每个内部类的事先只调用一次,所以可以用匿名内部类,外部也不会被污染

protocol PersonProtocol {
    func hello()
}
let closure1: () -> () = {
    class NotSoAnonymousClass : PersonProtocol {
        func hello() {
            print(#line, #function, "Hello")
        }
    }
    let object = NotSoAnonymousClass()
    object.hello()
}
let closure2 = {
    class NotSoAnonymousClass : PersonProtocol {
        func hello() {
            print(#line, #function, "Hello Two")
        }
    }
    let object = NotSoAnonymousClass()
    object.hello()
}

调用方法,我放到了2个按钮里面,点击按钮执行

        closure1()
        closure2()

执行结果:
16 hello() Hello
25 hello() Hello Two

做法2

下面的做法跟上面差不多,跟java的做法基本一样,java是 new 出class的时候在{}里面重写了类里的实例方法.swift按照java的思路来写,让类实现协议,并且实现协议中的方法,但是swift语法不能在定义class类的时候,马上用()括号执行调用他,再复制给变量,语法不行,所以要先定义一个类.

protocol PersonProtocol2 {
    func hello(str: String) -> ()
}
/*
let obj = class Person2 : PersonProtocol2 { //这样编译会报错,解决方法如下
    func hello(str: String) -> () {
        
    }
}()
 */

//让类Person继承协议,并且重写空的方法,真正要调用有内容的方法的时候,我们在下面的匿名内部类里实现
class Person : PersonProtocol2 {
    func hello(str: String) -> () {

    }
}

var obj1:Person = {  //这里obj1:PersonProtocol2 也可以,因为都有hello方法,但是不知不指定类型,
    class Anonymous : Person { //在闭包内定义的类,是内部类,外部看不见这个名字,就变成了匿名内部类,这个实现方法,跟java最像,返回的也是一个实力对象
        override func hello(str: String) -> ()  {
            print("开口说:",str)
        }
    }
    return Anonymous()
}()

调用方法:

obj1.hello(str: "你好")

执行结果:
开口说: 你好

做法3

  • 下面的方法是建立一个空的类,当闭包变量被赋值之前,表达式右边的闭包内容,修改了对象里的block变量fn,并且在init初始化的时候,给block变量传入block的执行内容. 如果看着比较拗口就直接看下面代码
  • 在类外执行的方法,实际上是调用对象的block
  • 注意EmptyClass没有继承任何类,所以不用写super.init()
  • EmptyClass2继承了NSObject,所以在init()中要先调用super.init,然后才能创建self对象.具体下面的closure3闭包变量的调用原理,我在代码里写了详细的注释,按照注释一步步看.
//下面的方法是建立一个空的类,在init初始化的时候,给block变量传入block的执行内容,执行的方法,实际上是调用对象的block

class EmptyClass {
    var fn: () -> () = { }// 这个类里面的fn是个block变量,并且用空的表达式初始化,如果不初始化,不能就必须在init中初始化这个变量
    
    //init方法,的参数是传入一个block,参数是传入当前类的对象,返回值也是当前类的对象

    init(callback:(EmptyClass)->EmptyClass) {
        callback(self)  //这里是省略写法,完整写法是 return callback(self)
        //给block callback传入的值是
    }
}

//closure3闭包初始化的时候,因为init已经获取了对象,所以直接可以修改对象下的block变量
let closure3 = EmptyClass { obj
    in
    obj.fn = {  print("closure3 run") }
    return obj
}
//继承自NSObject的类
class EmptyClass2:NSObject {
    var fn: () -> () = { }
    

    init(callback:(EmptyClass2)->EmptyClass2) {
        super.init()//因为本来有父类,就是NSObject,所以要使用之前必须先调用父类的指定初始化器
        callback(self)
        //给block callback传入的值是
    }
}
let closure4 = EmptyClass2 { obj in
    obj.fn = { print("closure4 run") }
    return obj
}
//类中的block变量带参数列表的情况如下
class EmptyClass3 {
    
    var fn: (_ str: String) -> () = { str in }//带参数的block变量
    
    init(callback: (EmptyClass3) -> EmptyClass3) {
        callback(self)
    }
}


let closure5 = EmptyClass3 { obj in
    obj.fn = { str
        in
        print("str=",str)
    }
    return obj
}

调用方法:

        closure3.fn()
        closure4.fn()
        closure5.fn("abc123")

执行结果:
closure3 run
closure4 run
str= abc123

总结

匿名内部类这种做法的目的:
1是为了偷懒,不想每次调用一个重写的实力方法都重写继承一个类再重写
2.避免污染类外的代码,内部类,保证了外部不会访问到,并且出现重名,因为作用域不一样,也会调用不同的方法
3.某些框架大佬再用,如果看不懂,就理解不了思想

demo代码下载

下面是我上面写的demo代码,使用xcode 12.3打开项目:
demo代码

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值