web-dev-qa-db-ja.com

Objective-CからSwiftタイプのプロパティにアクセスできません

SwiftクラスのDouble? Objective-Cのプロパティ。

class BusinessDetailViewController: UIViewController {

    var lat : Double?
    var lon : Double?

    // Other elements...
}

別のView Controllerで、次のようにlatにアクセスしようとしています:

#import "i5km-Swift.h"
@interface ViewController ()

@property (strong, nonatomic) BusinessDetailViewController *businessDetailViewController;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.businessDetailViewController = [[BusinessDetailViewController alloc] initWithNibName:@"BusinessDetailViewController" bundle:nil];
    self.businessDetailViewController.lat = businessArray[1]; /* THIS GIVES ME AN ERROR */
}

そして私は得ています

タイプ「BusinessDetailViewController *」のオブジェクトにプロパティ「lat」が見つかりません

このプロパティにアクセスできないのはなぜですか?私は何が欠けていますか?

60
tranvutuan

非Objective-C型のオプション値はObjective-Cにブリッジされません。つまり、以下のTestClassの最初の3つのプロパティwouldはObjective-Cで使用できますが、4番目は使用できません。

class TestClass: NSObject {
    var nsNumberVar: NSNumber = 0      // obj-c type, ok
    var nsNumberOpt: NSNumber?         // optional obj-c type, ok
    var doubleVar: Double = 0          // bridged Swift-native type, ok
    var doubleOpt: Double?             // not bridged, inaccessible
}

Objective-Cコードでは、次のような最初の3つのプロパティにアクセスします。

TestClass *optTest = [[TestClass alloc] init];
optTest.nsNumberOpt = @1.0;
optTest.nsNumberVar = @2.0;
optTest.doubleVar = 3.0;

あなたの場合、latlongを非オプションに変換するか、NSNumberのインスタンスに切り替えることができます。


2番目のアプローチ(latおよびlonNSNumber型のオプションではないプロパティに切り替える)を行う場合、Objective-Cコードに注意する必要があることに注意してください- Swiftコンパイラはnilをオプションでないプロパティに割り当てることを防ぎますが、Objective-Cコンパイラはnilの値を許可することに関して何の問題もありませんSwiftコードに実行時に潜入する可能性のないコードに潜入します。TestClassでこのメソッドを検討してください。

extension TestClass {
    func badIdea() {
        // print the string value if it exists, or 'nil' otherwise
        println(nsNumberOpt?.stringValue ?? "nil")

        // non-optional: must have a value, right?
        println(nsNumberVar.stringValue)
    }
}

両方のプロパティの値で呼び出された場合、これは正常に機能しますが、Objective-CコードからnsNumberVarnilに設定されている場合、実行時にクラッシュします。 チェックする方法はありません使用前にnsNumberVarnilであるかどうかに注意してください!

TestClass *optTest = [[TestClass alloc] init];
optTest.nsNumberOpt = @1.0;
optTest.nsNumberVar = @2.0;
[optTest badIdea];
// prints 1, 2

optTest.nsNumberOpt = nil;
optTest.nsNumberVar = nil;
[optTest badIdea];
// prints nil, then crashes with an EXC_BAD_ACCESS exception
105
Nate Cook

プロパティがSwiftプロトコルタイプの場合、@objcその前。

例:

class Foo: UIViewController {
   var delegate: FooDelegate?
   ...
}

@objc protocol FooDelegate {
   func bar()
}
14
dmzza

オプションはSwift特定の機能、obj-cでは使用不可。オプションのクラスインスタンスは、nilオプションをnil値にマップできるが、値の型(int、floatなど) not参照型であるため、これらの型の変数は参照を格納せず、値自体を格納します。

解決策があるかどうかはわかりません-可能な回避策は、nil値を未使用のデータ型値にマッピングするオプションでないプロパティを作成することです(インデックスを表す場合は-1、座標を表す場合は999999):

class Test {
    var lat : Double? {
        didSet {
            self._lat = self.lat != nil ? self.lat! : 999999
        }
    }
    var lon : Double? {
        didSet {
            self._lon = self.lon != nil ? self.lon! : 999999
        }
    }

    var _lat: Double = 99999999
    var _lon: Double = 99999999
}

これにより、_latプロパティと_lonプロパティがobj-cに公開されます。

私はこれを試したことがないので、うまくいくかどうかをお知らせください。

3
Antonio

[UInt?Int? または Double?プロパティ]は、Objective-Cで型を表すことができないため、@ objcとしてマークできません。

ただし、次のようにNSNumberで「ラップ」することは可能です。

class Foo {
    var bar:Double?
}

// MARK: Objective-C Support
extension Foo {
    /// bar is `Double?` in Swift and `(NSNumber * _Nullable)` in Objective-C
    @objc(bar)
    var z_objc_bar:NSNumber? {
        get {
            return bar as NSNumber?
        }
        set(value) {
            bar = value?.doubleValue ?? nil
        }
    }
}
1
Axel Guilmin