无法从 Swift 代码访问 Objective-C 单例的数组
Posted
技术标签:
【中文标题】无法从 Swift 代码访问 Objective-C 单例的数组【英文标题】:Cannot access Objective-C singleton's array from Swift code 【发布时间】:2019-03-04 23:28:34 【问题描述】:我在单例中创建了一个数组,以便从我的代码的多个部分将对象写入其中。方法如下:
// in singleton.h
#import <UIKit/UIKit.h>
// make globally accessible array
@interface MyManager : NSObject
NSMutableArray *imgArray;
@property (nonatomic, retain) NSMutableArray *imgArray;
+ (id)sharedManager;
@end
// in singleton.m
#import "singleton.h"
对于我的 .m 文件:
@implementation MyManager
@synthesize imgArray;
#pragma mark Singleton Methods
+ (id)sharedManager
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
sharedMyManager = [[self alloc] init];
);
return sharedMyManager;
- (id) init
if (self = [super init])
self.imgArray = [NSMutableArray new];
NSLog(@"initialized");
return self;
@end
我可以从我的目标 C 代码中访问名为 imgArray 的数组。但是,当我这样做时,我很快就会得到一个错误:
let array = MyManager.sharedManager()
array.imgArray.add("hello world") . (!!!) Value of type 'Any?' has no member 'imgArray'
我可以访问MyManager.sharedManager()
,但是为什么我不能像在目标C中那样访问imgArray
?
【问题讨论】:
【参考方案1】:您应该将其声明为instancetype
或MyManager *
。例如
+ (MyManager *)sharedManager;
或
+ (instancetype)sharedManager;
几个建议:
单例的 Swift 约定是使用 shared
的类属性名称,而不是 sharedManager()
的类方法。当你在 Objective-C 中声明它时,你可能想要明确地说它是一个类属性:
@property (class, readonly, strong) MyManager *sharedManager NS_SWIFT_NAME(shared);
这不会改变任何 Objective-C 的行为,但在 Swift 中,你可以这样做:
let manager = MyManager.shared
manager.images.add(image)
这会产生更简洁和惯用的 Swift 代码。
我建议您审核 Objective-C 的可空性。即,确认什么可以是nil
,什么不能。因为imgArray
(我可能只是称之为images
)和sharedManager
都不能是nil
,所以我只会使用NS_ASSUME_NONNULL_BEGIN
/END
宏告诉编译器“除非我另有说明,假设这个属性不能是nil
”:
// MyManager.h
@import UIKit;
NS_ASSUME_NONNULL_BEGIN
@interface MyManager : NSObject
@property (nonatomic, strong) NSMutableArray <UIImage *> *images;
@property (class, readonly, strong) MyManager *sharedManager NS_SWIFT_NAME(shared);
@end
NS_ASSUME_NONNULL_END
通过告诉编译器这两个不能是 nil
,这意味着您将不得不在 Swift 代码中减少不必要的可选项解包。
顺便说一句,请注意我没有声明实例变量。 (如果你确实需要,我不建议在公共接口中声明它。)Objective-C 现在将自动为我们合成支持我们属性的 ivars。 (所以我的属性 images
将有一个名为 _images
的 ivar,它将为我合成。)而且您也不需要/想要 @synthesize
行:
// MyManager.m
#import "MyManager.h"
@implementation MyManager
+ (instancetype)sharedManager
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
sharedMyManager = [[self alloc] init];
);
return sharedMyManager;
- (instancetype)init
if (self = [super init])
self.images = [NSMutableArray new];
NSLog(@"initialized");
return self;
@end
【讨论】:
【参考方案2】:将+ (id)sharedManager;
更改为+ (MyManager *)sharedManager;
。否则 Swift 不知道 sharedManager
是什么类型的对象,它会假定它是 Any
。
【讨论】:
或者instancetype
,而不是id
。以上是关于无法从 Swift 代码访问 Objective-C 单例的数组的主要内容,如果未能解决你的问题,请参考以下文章
无法从 Objective-C 视图控制器访问 Swift var - iOS
项目在 Swift 中时无法从 Objective-C 访问 swift 类
Objective C to Swift代码转换,似乎无法在Swift中正确处理字节