How to declare Objective-C method with custom Swift class in it - swift

I want to declare an Objective-C method with a custom Swift class as one of it's arguments, like this:
+ (void)doCalculationsWithACustomSwiftObject:(CustomSwiftClass *)swiftObject andADictionanary:(NSDictionary *)ordinaryDictionary;
The aim is to call this method from Swift, pass an instance of the custom class "CustomSwiftClass.swift" so that the Objective-C code can access its properties. Is it possible, and if so, how do I declare the "CustomSwiftClass" to make the compiler accept it?

A couple of thoughts:
To make Swift class accessible to your Objective-C code, you have to import the system generated header. As the documentation says:
When you import Swift code into Objective-C, you rely on an Xcode-generated header file to expose those files to Objective-C. This automatically generated file is an Objective-C header that declares the Swift interfaces in your target. It can be thought of as an umbrella header for your Swift code. The name of this header is your product module name followed by adding "-Swift.h". (You’ll learn more about the product module name later, in Naming Your Product Module.)
For example, your Objective-C file would import this generated header:
#import "MyApp-Swift.h"
For more information, see Importing Swift into Objective-C section of the Using Swift with Cocoa and Objective-C: Mix and Match
If you're not seeing the xxx-Swift.h file, double check your target settings:
(Note, I searched for "swift" in the settings to narrow down the results.)
As you'll see, the following are all set:
"Install Objective-C Compatibility Header" is set to "Yes";
The "Objective-C Generated Interface Header Name" is set (and matches what I imported into my Objective-C code);
The "Objective-C Bridging Header" is also specified.
Note, the Objective-C bridging header is ostensibly solely for the purpose of making the Objective-C classes available to the Swift code (and you're currently trying to accomplish the converse), but I notice that this affects what code is generated in the compatibility header, too. So make sure you have a bridging header, too.
Of course, make sure your Swift file is included in the list of compile sources:
And make sure the class is subclassed from NSObject:
import UIKit
class MyObject: NSObject {
var text: String?
var value: Int = 0
}
Note, some Swift types are not available to Objective-C code. For example, Objective-C cannot not use some optional types (e.g. an optional type such as Int? will not work, whereas an optional class type of String? will). So if you are seeing the class, but not some of the properties, make sure they're Objective-C compatible.
But I gather from your question that you're having more fundamental problems, that you're not finding the -Swift.h header at all. But once you solve that, this is a consideration for individual properties.

Related

Category Or Extention -- Which one will have precedence

I write awakeFromXib in UILabel category plus Swift UILabel extension.
Now I add one brand new UILabel on ViewController (no outlet created).
awakeFromNib is being called from the category and not from Swift extension.
Please guide which one will have precedence and in what circumstances.
Note: ViewController parent class is written in Swift.
First of all - neither Swift extensions nor Objective-C categories should be used to override non-inherited methods (methods already defined in the class being extended). Apple mentions it in both Swift Developer Guide..:
Extensions can add new functionality to a type, but they can’t override existing functionality.
..And Programming with Objective-C documentations:
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime.
If you look for a written "contract", it's emphasised in the quoted text above: if a method is defined in an extensions of a Swift class which itself is a subclass of NSObject (and UILabel is indirect subclass of NSObject) it gets dispatched with messaging mechanism (just like a method defined in an Objective-C category). Thus both methods follow the same Objective-C rules, dispatched the same way, have the same name and the same set of arguments. According to the Apple's own documentation in regards to Objective-C categories it means that the behavior is undefined.
You can probably find empirically some general pattern, but it is not guaranteed to be consistent (can work differently between or even within the same application session) and is a subject to change in future releases.
P.S. It's also double-discouraged to "shadow" Cocoa/Cocoa touch framework classes methods since you may end with suppressing the class own implementation from being called and consequently breaking the dependent logic.

How to inherit from NSTokenAttachmentCell in Swift?

In Swift (and objective-c), you cannot normally subclass NSTokenAttachmentCell. However, if I create a bridging header and define a header for NSTokenAttachmentCell, I can then subclass it in Swift.
Here is an example of it in objective-c. NSTokenAttachmentCell isn't publicly available. However, if you create a header file for it, you can subclass it. You can't create header files in Swift. Other than creating one in a bridging header, is there a way to do this in Swift?
#import <Cocoa/Cocoa.h>
#import "NSTokenAttachmentCell.h"
#interface BWTokenAttachmentCell : NSTokenAttachmentCell {}
#end
I created a Swift system module swift package init --type executable. The only file in addition to the standard SPM files was the custom header file that wasn't publicly available.
I can now use the system module package as a dependency and subclass the Apple class that you can't normally subclass.
Here is the full example.
git clone https://github.com/saltzmanjoelh/TokenExample && cd TokenExample && swift test
You will see the correct inheritance
Success: - <TokenExample.CustomTokenAttachmentCell: 0x7fc1be803d10> #0
- super: NSTokenAttachmentCell
- super: NSTextAttachmentCell
- super: NSCell
- super: NSObject
I used these two guides as a reference:
ship-c-code-with-swift-packages
importing-c-library-into-swift
The simple answer is no, you can't inherit from private classes.
Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.
source: https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

Must NSSecureCoding-implementing classes be in shared framework to work with XPC?

While following Creating XPC Services guide in Swift and trying to pass custom Foo class I found that in order for this to work it must be in a dynamic library. When it's embedded into both targets the connection to service fails with 4097 code. Same happens if Foo is in a static lib.
I can't seem any references to this requirement and guessing this is due to the fact that security identifies them as different objects while decoding. Is this true? Any more concrete info on this?
The problem lays with Swift name mangling, which results in different class names in different targets, so when XPC decoder tries to securely decode a received object it sees a different class name from specified and fails.
With obj.io XPC example compiled Swift #objc class Foo: NSObject, NSSecureCoding class in app and service targets has #class Foo : NSObject<NSSecureCoding> and #class _TtC15ImageDownloader3Foo : NSObject<NSSecureCoding> signatures, respectively.
To avoid this simply add explicit Objective-C name in #objc(Foo) tag, which will produce the same #class Foo : NSObject<NSSecureCoding> class signature in both targets.

Swift Module - When Importing I get "Redefinition of 'x' as different kind of symbol"

While developing a swift Cocoapod we started seeing this error appear when importing it into other projects:
"Redefinition of 'Category' as different kind of symbol"
There is a name spacing conflict in our module when it generates the Swift umbrella header
After doing some research we found that you can refine how your umbrella header names classes
See: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID35
Under "Configuring Swift Interfaces in Objective-C" section
In some cases, you need finer grained control over how your Swift API is exposed to Objective-C. You can use the #objc(name) attribute to change the name of a class, property, method, enumeration type, or enumeration case declaration in your interface as it’s exposed to Objective-C code.
So this worked
#objc(YGCategory)
class Category: NSObject {
//etc...
}

Why does adding 'dynamic' fix my bad access issues?

I'm having a strange issue that appeared with iOS 8 Beta 5 (this issue did not occur with previous versions).
I tried to create an empty project and try to replicate the issue, but I'm unable to do so, so I'm not quite sure where the issue lies.
What I'm seeing is that attempting to access methods of a custom NSManagedObject subclass results in a strange EXC_BAD_ACCESS error.
For example:
var titleWithComma: String {
return "\(self.title),"
}
This method, out of many others, causes this issue when called. However, adding a dynamic keyword before it makes the issue go away:
dynamic var titleWithComma: String {
return "\(self.title),"
}
I know I'm not giving enough info, because I honestly don't know how to pinpoint the actual issue, but can anyone explain what is possibly happening, and why adding dynamic might resolve this issue?
From Swift Language Reference (Language Reference > Declarations > Declaration Modifier)
Apply this modifier to any member of a class that can be represented
by Objective-C. When you mark a member declaration with the dynamic
modifier, access to that member is always dynamically dispatched using
the Objective-C runtime. Access to that member is never inlined or
devirtualized by the compiler.
Because declarations marked with the dynamic modifier are dispatched
using the Objective-C runtime, they’re implicitly marked with the objc
attribute.
It means that your property/method can be accessed by Objective-C code or class. Normally it happens when you sub-classing a Swift class of Objective-C base class.
This is from the prerelease Swift / Objective-C interoperability documentation:
Implementing Core Data Managed Object Subclasses
Core Data provides the underlying storage and implementation of properties in subclasses of the NSManagedObject class. Add the #NSManaged attribute before each property definition in your managed object subclass that corresponds to an attribute or relationship in your Core Data model. Like the #dynamic attribute in Objective-C, the #NSManaged attribute informs the Swift compiler that the storage and implementation of a property will be provided at runtime. However, unlike #dynamic, the #NSManaged attribute is available only for Core Data support.
So, because of some of the Objective-C runtime features that Core Data uses under the covers, Swift properties need to be specially annotated.