21

I started writing Swift extensions on my view controllers. So I have three files right now:

My header file, ViewController.h:

@interface MyViewController : UIViewController

@end

My Obj-C implementation file, ViewController.m:

@interface MyViewController () <UIScrollViewDelegate>
@property (strong, nonatomic) UIScrollView *scrollView;
@end

@implementation MyViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    self.scrollView = [[UIScrollView alloc] init];
    [self customiseScrollView]; //This is Swift method called from Obj-C file
}

@end

And finally, ViewController.swift:

extension MyViewController {

    func customiseScrollView() {

    }
}

My question is, is it possible to access my Obj-C properties from my Swift implementation file? Every time I refer to it, I got an error:

Value of type 'MyViewController' has no member 'scrollView'

Bonus 1: Can someone also clarify if the Swift component can see what the .m is a delegate of as well. (To clarify, doing scrollView.delegate = self in Swift is a compile error because the Swift file does not realise that the .m file is a UIScrollViewDelegate).

Bonus 2: Can Swift extension file call Obj-C methods that are declared from the .m counterpart?

Enrico Susatyo
  • 19,372
  • 18
  • 95
  • 156
  • 2
    If you want to access the scrollView property from Swift then you should put it into the public interface in the .h file. – Re Bonus 1: *"what the .m is a delegate of"* makes no sense. A delegate is an object, not a file. – Re Bonus 2: Yes, [How to call Objective C code from Swift](http://stackoverflow.com/questions/24002369/how-to-call-objective-c-code-from-swift) is #2 on the frequent tab of the [swift] questions. – Martin R Oct 22 '15 at 07:52
  • @MartinR Thanks Martin, I edited that part of the question to clarify what I meant. I also realised that I can access the properties when I put it in .h file, but I didn't want to do that because that exposes the property to my other Obj-C classes too. – Enrico Susatyo Oct 22 '15 at 08:08
  • 1
    Declarations in the .m file are only visible in that file. The same would happen if you define an extension in a separate Objective-C file, it is not a Swift issue. – Martin R Oct 22 '15 at 08:12

5 Answers5

17

I think that you can't access private properties from extension. Your scrollView property is in .m file, not .h - which means it's private and it's not visible from extension file.

Solution: move

@property (strong, nonatomic) UIScrollView *scrollView;

to your header file.

Kubba
  • 3,390
  • 19
  • 34
  • 1
    Yes, this works! But I was hoping I don't have to do this, because I don't want these properties to be accessible from my other Obj-C classes. – Enrico Susatyo Oct 22 '15 at 08:09
  • 4
    @EnricoSusatyo It might be a good idea to make it `readonly` in the header and `readwrite` only in the implementation file. – Sulthan Dec 26 '18 at 15:49
6

You can access internal objc properties and methods if you declare the objc class extension in a separate header and include that header in the bridging header.

MyClass.h

@interface MyClass : NSObject

@property (nonatomic, copy, readonly) NSString *string;

@end

MyClass+Private.h

#import "MyClass.h"

@interface MyClass ()

@property (nonatomic, copy) NSString *string;

@end

MyClass.m

#import "MyClass+private.h"

@implementation MyClass

//...

@end

Project-Bridging-Header.h

#import "MyClass.h"
#import "MyClass+Private.h"
Nico Spencer
  • 940
  • 6
  • 11
1

In Swift, private properties are not accessible from another file. This is the meaning of private in Swift. For example:

file1.swift

class MyClass {
    private var privateProperty: String = "Can't get to me from another file!"
}
extension MyClass: CustomStringConvertible {
    var description: String {
        return "I have a `var` that says: \(privateProperty)"
    }
}

file2.swift

extension MyClass {
    func cantGetToPrivateProperties() {
        self.privateProperty // Value of type 'MyClass' has no memeber 'privateProperty'
    }
}

A property declared in the implementation of an Objective-C class is a private property. As such, the property cannot be accessed from a Swift extension since this will be necessarily from a different (.swift) file...

Milos
  • 2,728
  • 22
  • 24
  • Note that in your example, conformance to a delegate protocol is also declared privately, so this will not be visible from a Swift extension for the same reason. Likewise with private methods... However, if your `scrollView` takes part in a window hierarchy, you could get to it through its `public`ly or `internal`ly declared superview... – Milos Oct 22 '15 at 08:28
-1

You can. All you need is to create a bridging objective C header.

Per Apple Documentation:

To import a set of Objective-C files in the same app target as your Swift code, you rely on an Objective-C bridging header to expose those files to Swift. Xcode offers to create this header file when you add a Swift file to an existing Objective-C app, or an Objective-C file to an existing Swift app.

Abhinav
  • 37,684
  • 43
  • 191
  • 309
-1

Just create a Bridging-Header file and later import your ObjC file in it, like:

#import <objectivec.h>

Later in your swift file:

var a = objectivec()
a.method_from_those_file

For more information read Apple Doucmentation from here.

Orkhan Alizade
  • 7,379
  • 14
  • 40
  • 79