【OC/Swift混编】接口中数据类型的建议(二):使用层面分析
作者:互联网
本文目录
一、前言
上文说到,在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