ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-29 10:02:22  阅读:189  来源: 互联网

标签:String 数据类型 OC private init func Swift Any


本文目录

一、前言

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

  • 1.尽可能多地使用不可变类型,尽可能不使用可变类型。(建议:NSString*,NSArray*,- NSDictionary*)
  • 2.尽可能使用泛型指定不可变类型中元素的类型。(建议:NSDictionary<NSString*,id>)
  • 3.对于值类型尽可能不要使用其指针(Bool*),对于指针类型尽可能不要使用其二级指针。(NSString**)

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

二、代码结构

假设有一个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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有