Unable to access Swift 4 class from Objective-C: "Property not found on object of type"

IosObjective CSwiftXcodeSwift4

Ios Problem Overview


Using the latest Xcode 9 beta, I'm seemingly completely unable to access properties on Swift classes. Even odder, I can access the class itself to instantiate it or whatever, but completely unable to access properties on it.

So if I have this Swift class:

import UIKit

class TestViewController: UIViewController {
    var foobar = true
}

And I try to do this:

TestViewController *testViewController = [[TestViewController alloc] init]; // success
testViewController.foobar; // error

What exactly am I doing wrong? New project with Xcode 9.

Ios Solutions


Solution 1 - Ios

The rules for exposing Swift code to Objective-C have changed in Swift 4. Try this instead:

@objc var foobar = true

As an optimization, @objc inference have been reduced in Swift 4. For instance, a property within an NSObject-derived class, such as your TestViewController, will no longer infer @objc by default (as it did in Swift 3).

Alternatively, you could also expose all members to Objective-C at once using @objcMembers:

@objcMembers class TestViewController: UIViewController {
    ...
}

This new design is fully detailed in the corresponding Swift Evolution proposal.

Solution 2 - Ios

Swift 3.2/4.0 / XCode 9.1

You you set swift3.2 in project settings ( //:configuration = Debug SWIFT_VERSION = 3.2 )

you can use your code,(using the correct import file in objc, see below). If You set project to swift 4.0 ( //:configuration = Debug SWIFT_VERSION = 4.0 )

You must prepend @objc for every property.

So:

Swift 3.2:

// MyClass.swift

@objc class MyClass: NSObject{
	
	var s1: String?
	@objc var s2 : String?
}


//

//  ViewController.m

import "MixingObjCAndSwift-Swift.h"
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
	[super viewDidLoad];    	
	MyClass * mc = [MyClass new];
	NSString * s1 = mc.s1;
	NSString * s2 = mc.s2;
}

works.

Swift 4.0:

// MyClass.swift

@objc class MyClass: NSObject{
	
	var s1: String?
	@objc var s2 : String?
}


.....  
- (void)viewDidLoad {
	[super viewDidLoad];    	
	MyClass * mc = [MyClass new];
	NSString * s1 = mc.s1;
	NSString * s2 = mc.s2;
}

does NOT works: compiler fails:

/Users....ViewController.m:24:21: Property 's1' not found on object of type 'MyClass *'

as s1 is not prepended with @objc.

You must write:

@objc class MyClass: NSObject{
	
	@objc var s1: String?
	@objc var s2 : String?
}

(As a side-note: in C/C++/ObJC file, put always system/general *h files before your "local" class headers.)

Swift 4

just add @objcMembers before class @objcMembers class MyClassObject: NSObject { var s1: String! var s2: String!

} Swift evolutionenter link description here

Solution 3 - Ios

As for Swift 5.1 I found that "@objc" is not enough, but also make it public "@objc public":

@objc public class SomeClass: NSObject {
    @objc public let amount: NSNumber
...

Solution 4 - Ios

  1. When you add a swift file in your Objective-C project, Xcode will prompt to add Objective-C bridging header file, so allow the header file to be created.
  2. In your Objective-C implementation file where you want to access the TestViewController property foobar. Use the following import syntax and replace the ProjectName with your project.

> #import "ProjectName-Swift.h"

Objective-C implementation file:

#import "ViewController.h"
#import "ProjectName-Swift.h"

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    TestViewController *testViewController = [[TestViewController alloc] init]; // success
    BOOL prop = testViewController.foobar;
    NSLog(@"Property: %d", prop);
}

@end

For more details go through the Apple Documents

Solution 5 - Ios

Xcode 10.2 | Swift 4 Adding @objcMembers before class solved my problem.

@objcMembers class MyClass:NSObject {
   var s1: String!
   var s2: NSMutableArray!
}

Solution 6 - Ios

I also encountered with this problem in swift 3.0

class declaration was like that

class ClassA {
//statements
}

above class was not accessible in Objective C code and it was also not registered in -Swift.h

once I inherited from NSObject like this:

class ClassA : NSObject {
//statements
} 

the class was accessible in Objective c and got registered with -Swift.h

This solution is useful when you don't want to avoid inheritance from NSobject class.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDoug SmithView Question on Stackoverflow
Solution 1 - IosPaulo MattosView Answer on Stackoverflow
Solution 2 - IosingcontiView Answer on Stackoverflow
Solution 3 - IosprotspaceView Answer on Stackoverflow
Solution 4 - IosRahul KumarView Answer on Stackoverflow
Solution 5 - IosP AnandhakumarView Answer on Stackoverflow
Solution 6 - IosPrabhat KaseraView Answer on Stackoverflow