无法从Swift代码访问Objective-C单例数组

时间:2019-03-04 23:28:35

标签: objective-c swift bridging-header

我在一个单例中制作了一个数组,以将代码的多个部分写入对象。方法如下:

// 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

2 个答案:

答案 0 :(得分:2)

+ (id)sharedManager;更改为+ (MyManager *)sharedManager;。否则,Swift不知道对象sharedManager是哪种类型,它将假定它是Any

答案 1 :(得分:2)

您应将其声明为instancetypeMyManager *。例如

+ (MyManager *)sharedManager;

+ (instancetype)sharedManager;

一些建议:

  1. 单例的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代码。

  2. 我建议您审核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代码中减少不必要的可选选项的包装。

  3. 顺便说一句,请注意,我没有声明实例变量。 (如果您确实需要它,我不建议在公共界面中声明它。)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