其他分享
首页 > 其他分享> > 【OC/Swift混编】接口中数据类型的建议(二):使用层面分析

【OC/Swift混编】接口中数据类型的建议(二):使用层面分析

作者:互联网

本文目录

一、前言

上文说到,在OC/Swift混编下,对属性或参数的数据类型有如下建议:

本文将通过一个简单的实例来解释为什么要这样做。

二、代码结构

假设有一个OC的模型类如下:

@interface TestDataModel : NSObject

@property (nonatomic, strong) NSDictionary                      *dict1;
@property (nonatomic, strong) NSMutableDictionary               *dict2;
@property (nonatomic, strong) NSDictionary<NSString*,id>        *dict3;
@property (nonatomic, strong) NSMutableDictionary<NSString*,id> *dict4;
@property (nonatomic, strong) NSDictionary                      *errorTypeDict;

@property (nonatomic, assign) BOOL boolValue;
@property (nonatomic, assign) BOOL *boolPtrValue;

-(void)printBool:(BOOL)boolValue;
-(void)printBoolPtr:(BOOL*)boolPtrValue;

@end

@implementation TestDataModel

-(instancetype)init {
    if( self=[super init] ) {
        self.dict1 = @{
            @"strKey":@"strValue",
            @"boolKey":@(YES),
            @"dictKey":@{@"key":@"value"}
        };
        self.dict2 = [NSMutableDictionary dictionaryWithDictionary:self.dict1];
        self.dict3 = [self.dict1 copy];
        self.dict4 = [NSMutableDictionary dictionaryWithDictionary:self.dict1];
        self.errorTypeDict = @{@1:@1,@2:@2,@3:@3};
        self.boolValue = YES;
        self.boolPtrValue = &_boolValue;
    }
    return self;
}

-(void)printBool:(BOOL)boolValue
{
    NSLog(@"boolValue = %d",boolValue);
}

-(void)printBoolPtr:(BOOL*)boolPtrValue
{
    if( boolPtrValue==nil ){
        NSLog(@"boolPtrValue = nil");
        return ;
    }
    NSLog(@"boolValue = %d",*boolPtrValue);
}

main.m中调用Swift类的代码如下:

#import "studyObjc-Swift.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        [[[TestSwift alloc] init] main];
    }
    return 0;
}

Swift的代码框架如下:

import Foundation

@objcMembers
class TestSwift:NSObject {
    
    private func testDict1(){
       
    }
    
    private func testDict2(){
        
    }
    
    private func testDict3(){
        
    }

    private func testDict4(){

    }
    
    private func testErrorTypeDict(){
        
    }
    
    private func testBool(){
        
    }
    
    private func testBoolPtr(){
        
    }
    
    public func main(){
        testDict1()
        testDict2()
        testDict3()
        testDict4()
        testErrorTypeDict()
        testBool()
        testBoolPtr()
    }
}

三、不同数据类型下在Swift中的用法

接下来,我们开始尝试在Swift代码中调用OC的TestDataModel

1.在Swift中使用NSDictionary

首先,如果我们在testDict1方法中,直接采取如下写法,编译。

private func testDict1(){
        let swDict1:[String:Any] = TestDataModel.init().dict1
        print(swDict1)
}

此时,编译器会报错:

Cannot assign value of type '[AnyHashable : Any]' to type '[String : Any]'

原因是,NSDictionary没有使用泛型去指定类型时,默认情况下,在Swift中会认为其类型是[AnyHashable : Any]

此时,为了能将dict1的值成功赋值给swDict1,我们必须做一个类型转换,代码如下:

private func testDict1(){
        let swDict1:[String:Any] = TestDataModel.init().dict1 as! [String:Any]
        print(swDict1)
}

It Works,看起来不错。

但实际上,当你看到as!时,你就应该意识到,当dict1的强制类型转换到[String:Any]发生失败,那么程序就会crash!!!

2.类型转换失败导致程序崩溃

为了证明这一点,接下来,我们在testErrorTypeDict方法里,实现如下写法:

private func testErrorTypeDict(){
        let swErrorTypeDict:[String:Any] = TestDataModel.init().errorTypeDict as! [String:Any]
        print(swErrorTypeDict)
}

编译,运行,程序崩溃,并打印如下信息:

Could not cast value of type 'Swift.AnyHashable' (0x7fff81603d58) to 'Swift.String' (0x7fff81606180).

3.在Swift中使用NSMutableDictionary

接下来,我们尝试在Swift中使用NSMutableDictionary类型的属性,在使用时,同样的也需要对其进行强制类型转换,其代码如下:

private func testDict2(){
        let swDict2:[String:Any] = TestDataModel.init().dict2 as! [String:Any]
        print(swDict2)
}

4.在Swift中使用NSDictionary+范型

最后,我们来尝试在Swift中使用NSDictionary<NSString*,id>类型的属性,代码如下:

private func testDict3(){
        let swDict3:[String:Any] = TestDataModel.init().dict3
        print(swDict3)
}

我们看到,其赋值过程是无比的丝滑、顺利,在代码层面不需要任何的类型转换。

5.在Swift中使用NSMutableDictionary+范型

那么,问题来了,NSMutableDictionary<NSString*,id>可以很丝滑、很顺利的直接赋值吗?
答案是否定的,其代码如下:

private func testDict4(){
        let swDict4:[String:Any] = TestDataModel.init().dict4 as! [String : Any]
        print(swDict4)
}

6.在Swift中使用Bool、Bool*

写的有些累了,省略废话,对于最后一条建议的反例如下:

private func testBool(){
        let swBool:Bool = true
        TestDataModel.init().print(swBool)
}
private func testBoolPtr(){
        let swBool:ObjCBool = true
        let swBoolPtr = UnsafeMutablePointer<ObjCBool>.init(&swBool)
        TestDataModel.init().printBoolPtr(swBoolPtr)
}

我们发现,在OC中基本数据类型一旦使用到指针时,就需要在Swift中手工创建UnSafeMutablePointer对象,使用起来是非常麻烦的,因此,尽量避免在OC的方法的参数或者属性中使用指针/二级指针。

从本文例子中,我们可以从Swift使用层面深刻体会到前文提到的那些建议的好处,那么,OC对象转Swift对象背后是怎么实现的呢?请参考下文。

四、附录:Swift完整代码

Swift的完整代码

import Foundation

@objcMembers
class TestSwift:NSObject {
    
    private func testDict1(){
        let swDict1:[String:Any] = TestDataModel.init().dict1 as! [String:Any]
        print(swDict1)
    }
    
    private func testDict2(){
        let swDict2:[String:Any] = TestDataModel.init().dict2 as! [String:Any]
        print(swDict2)
    }
    
    private func testDict3(){
        let swDict3:[String:Any] = TestDataModel.init().dict3
        print(swDict3)
    }
    
    private func testDict4(){
        let swDict4:[String:Any] = TestDataModel.init().dict4 as! [String : Any]
        print(swDict4)
    }

    private func testErrorTypeDict(){
//        let swErrorTypeDict:[String:Any] = TestDataModel.init().errorTypeDict as! [String:Any]
//        print(swErrorTypeDict)
    }
    
    private func testBool(){
        let swBool:Bool = true
        TestDataModel.init().print(swBool)
    }
    
    private func testBoolPtr(){
        var swBool:ObjCBool = true
        var swBoolPtr = UnsafeMutablePointer<ObjCBool>.init(&swBool)
        TestDataModel.init().printBoolPtr(swBoolPtr)
    }
    
    public func main(){
        testDict1()
        testDict2()
        testDict3()
        testErrorTypeDict()
        testBool()
        testBoolPtr()
    }
    
}

标签:String,数据类型,OC,private,init,func,Swift,Any
来源: https://blog.csdn.net/gaoben668/article/details/122672710