Using Objective-C Classes in Swift
If you have an existing class that you'd like to use, perform Step 2 and then skip to Step 5. (For some cases, I had to add an explicit #import <Foundation/Foundation.h
to an older Objective-C File.)
Step 1: Add Objective-C Implementation -- .m
Add a .m
file to your class, and name it CustomObject.m
.
Step 2: Add Bridging Header
When adding your .m
file, you'll likely be hit with a prompt that looks like this:
Click Yes!
If you did not see the prompt, or accidentally deleted your bridging header, add a new .h
file to your project and name it <#YourProjectName#>-Bridging-Header.h
.
In some situations, particularly when working with Objective-C frameworks, you don't add an Objective-C class explicitly and Xcode can't find the linker. In this case, create your .h
file named as mentioned above, then make sure you link its path in your target's project settings like so:
Note:
It's best practice to link your project using the $(SRCROOT)
macro so that if you move your project, or work on it with others using a remote repository, it will still work. $(SRCROOT)
can be thought of as the directory that contains your .xcodeproj file. It might look like this:
$(SRCROOT)/Folder/Folder/<#YourProjectName#>-Bridging-Header.h
Step 3: Add Objective-C Header -- .h
Add another .h
file and name it CustomObject.h
.
Step 4: Build your Objective-C Class
In CustomObject.h
#import <Foundation/Foundation.h>
@interface CustomObject : NSObject
@property (strong, nonatomic) id someProperty;
- (void) someMethod;
@end
In CustomObject.m
#import "CustomObject.h"
@implementation CustomObject
- (void) someMethod {
NSLog(@"SomeMethod Ran");
}
@end
Step 5: Add Class to Bridging-Header
In YourProject-Bridging-Header.h
:
#import "CustomObject.h"
Step 6: Use your Object
In SomeSwiftFile.swift
:
var instanceOfCustomObject = CustomObject()
instanceOfCustomObject.someProperty = "Hello World"
print(instanceOfCustomObject.someProperty)
instanceOfCustomObject.someMethod()
There is no need to import explicitly; that's what the bridging header is for.
Using Swift Classes in Objective-C
Step 1: Create New Swift Class
Add a .swift
file to your project, and name it MySwiftObject.swift
.
In MySwiftObject.swift
:
import Foundation
@objc(MySwiftObject)
class MySwiftObject : NSObject {
@objc
var someProperty: AnyObject = "Some Initializer Val" as NSString
init() {}
@objc
func someFunction(someArg: Any) -> NSString {
return "You sent me \(someArg)"
}
}
Step 2: Import Swift Files to ObjC Class
In SomeRandomClass.m
:
#import "<#YourProjectName#>-Swift.h"
The file:<#YourProjectName#>-Swift.h
should already be created automatically in your project, even if you can not see it.
Step 3: Use your class
MySwiftObject * myOb = [MySwiftObject new];
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);
myOb.someProperty = @"Hello World";
NSLog(@"MyOb.someProperty: %@", myOb.someProperty);
NSString * retString = [myOb someFunctionWithSomeArg:@"Arg"];
NSLog(@"RetString: %@", retString);
Notes:
If Code Completion isn't behaving as you expect, try running a quick build with ⌘⇧R to help Xcode find some of the Objective-C code from a Swift context and vice versa.
If you add a .swift
file to an older project and get the error dyld: Library not loaded: @rpath/libswift_stdlib_core.dylib
, try completely restarting Xcode.
While it was originally possible to use pure Swift classes (Not descendents of NSObject
) which are visible to Objective-C by using the @objc
prefix, this is no longer possible. Now, to be visible in Objective-C, the Swift object must either be a class conforming to NSObjectProtocol
(easiest way to do this is to inherit from NSObject
), or to be an enum
marked @objc
with a raw value of some integer type like Int
. You may view the edit history for an example of Swift 1.x code using @objc
without these restrictions.
Yes you can do it.
In Swift you can still use the "#if/#else/#endif" preprocessor macros (although more constrained), as per Apple docs. Here's an example:
#if DEBUG
let a = 2
#else
let a = 3
#endif
Now, you must set the "DEBUG" symbol elsewhere, though. Set it in the "Swift Compiler - Custom Flags" section, "Other Swift Flags" line. You add the DEBUG symbol with the -D DEBUG
entry.
As usual, you can set a different value when in Debug or when in Release.
I tested it in real code and it works; it doesn't seem to be recognized in a playground though.
You can read my original post here.
IMPORTANT NOTE: -DDEBUG=1
doesn't work. Only -D DEBUG
works. Seems compiler is ignoring a flag with a specific value.
Best Answer
some View
is an opaque result type as introduced by SE-0244 and is available in Swift 5.1 with Xcode 11. You can think of this as being a "reverse" generic placeholder.Unlike a regular generic placeholder which is satisfied by the caller:
An opaque result type is an implicit generic placeholder satisfied by the implementation, so you can think of this:
as looking like this:
In fact, the eventual goal with this feature is to allow reverse generics in this more explicit form, which would also let you add constraints, e.g
-> <T : Collection> T where T.Element == Int
. See this post for more info.The main thing to take away from this is that a function returning
some P
is one that returns a value of a specific single concrete type that conforms toP
. Attempting to return different conforming types within the function yields a compiler error:As the implicit generic placeholder cannot be satisfied by multiple types.
This is in contrast to a function returning
P
, which can be used to represent bothS1
andS2
because it represents an arbitraryP
conforming value:Okay, so what benefits do opaque result types
-> some P
have over protocol return types-> P
?1. Opaque result types can be used with PATs
A major current limitation of protocols is that PATs (protocols with associated types) cannot be used as actual types. Although this is a restriction that will likely be lifted in a future version of the language, because opaque result types are effectively just generic placeholders, they can be used with PATs today.
This means you can do things like:
2. Opaque result types have identity
Because opaque result types enforce a single concrete type is returned, the compiler knows that two calls to the same function must return two values of the same type.
This means you can do things like:
This is legal because the compiler knows that both
x
andy
have the same concrete type. This is an important requirement for==
, where both parameters of typeSelf
.This means that it expects two values that are both the same type as the concrete conforming type. Even if
Equatable
were usable as a type, you wouldn't be able to compare two arbitraryEquatable
conforming values with each other, for example:As the compiler cannot prove that two arbitrary
Equatable
values have the same underlying concrete type.In a similar manner, if we introduced another opaque type returning function:
The example becomes illegal because although both
foo
andbar
returnsome Equatable
, their "reverse" generic placeholdersOutput1
andOutput2
could be satisfied by different types.3. Opaque result types compose with generic placeholders
Unlike regular protocol-typed values, opaque result types compose well with regular generic placeholders, for example:
This wouldn't have worked if
makeP
had just returnedP
, as twoP
values may have different underlying concrete types, for example:Why use an opaque result type over the concrete type?
At this point you may be thinking to yourself, why not just write the code as:
Well, the use of an opaque result type allows you to make the type
S
an implementation detail by exposing only the interface provided byP
, giving you flexibility of changing the concrete type later down the line without breaking any code that depends on the function.For example, you could replace:
with:
without breaking any code that calls
makeP()
.See the Opaque Types section of the language guide and the Swift evolution proposal for further information on this feature.