Are public swift functions on ObjC objects dynamically or statically dispatched? - ios

Here's my example, let's say I have a custom UIView with a tap gesture recognizer that responds to this function:
func handleTap(tap: UITapGestureRecognizer) {
println("Tap!")
}
I generally prefer these to be private, so I mark it as such but it doesn't work. An #objc or dynamic specifier is required, like so:
dynamic private func handleTap(tap: UITapGestureRecognizer) {
println("Tap!")
}
This makes me believe that public functions are dynamic by default when added to an objective-c object. Is this the case? Please cite references if found.

The Swift compiler will try to prove that a call to a method can only end up with a single implementation. If it can prove this then it will use static and not dynamic dispatch. Use of the "final" or "private" keyword, and whole module optimisation, will help with this.

From Using Swift with Cocoa and Objective-C:
Requiring Dynamic Dispatch
While the #objc attribute exposes your
Swift API to the Objective-C runtime, it does not guarantee dynamic
dispatch of a property, method, subscript, or initializer. The Swift
compiler may still devirtualize or inline member access to optimize
the performance of your code, bypassing the Objective-C runtime. When
you mark a member declaration with the dynamic modifier, access to
that member is always dynamically dispatched. Because declarations
marked with the dynamic modifier are dispatched using the Objective-C
runtime, they’re implicitly marked with the #objc attribute.”

Related

Tell Swift compiler method as swift only

I have a swift class defined like this:
#objcMembers
public class MyURL: NSObject {
func concat(_ components: String...) -> MyURL {
concat(components)
}
/// Concat the specified components one by one.
func concat(_ components: [String]) -> MyURL {
components.forEach { let _ = value?.appendingPathComponent($0) }
return self
}
// All the other methods which are available for objc.
}
There are many methods inside which are available for objective-c, so I use the #objcMembers for class prefix directly, then swift compiler starts to complaint this:
Method 'concat' with Objective-C selector 'concat:' conflicts with previous declaration with the same Objective-C selector
They are exactly have the same function signature, but the latter one is only available for swift even if exposed. Now I'm looking for some compile flags to mark the latter concat method as swift only to tell the compiler to ignore the conflict error.
#objc and #objcMembers do that explicitly, so how to do it reverse?
https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#nonobjc
“nonobjc
Apply this attribute to a method, property, subscript, or initializer declaration to suppress an implicit objc attribute. The nonobjc attribute tells the compiler to make the declaration unavailable in Objective-C code, even though it’s possible to represent it in Objective-C.
Applying this attribute to an extension has the same effect as applying it to every member of that extension that isn’t explicitly marked with the objc attribute.
You use the nonobjc attribute to resolve circularity for bridging methods in a class marked with the objc attribute, and to allow overloading of methods and initializers in a class marked with the objc attribute.
A method marked with the nonobjc attribute can’t override a method marked with the objc attribute. However, a method marked with the objc attribute can override a method marked with the nonobjc attribute. Similarly, a method marked with the nonobjc attribute can’t satisfy a protocol requirement for a method marked with the objc attribute.”

When #objc and #nonobjc write before method and variable in swift?

When I declare static parameter in extension of class then I have to write #nonobjc before variable like:
#nonobjc static let test = "test"
and sometimes I have to write #objc before method, so what is use of #objc and #nonobjc in Swift.
Can anyone help me for this problem?
This is explained in the Apple's official documentation about Objective-C - Swift interoperability:
When you use the #objc(name) attribute on a Swift class, the class is
made available in Objective-C without any namespacing. As a result,
this attribute can also be useful when migrating an archivable
Objective-C class to Swift. Because archived objects store the name of
their class in the archive, you should use the #objc(name) attribute
to specify the same name as your Objective-C class so that older
archives can be unarchived by your new Swift class.
Conversely, Swift also provides the #nonobjc attribute, which makes a
Swift declaration unavailable in Objective-C. You can use it to
resolve circularity for bridging methods and to allow overloading of
methods for classes imported by Objective-C. If an Objective-C method
is overridden by a Swift method that cannot be represented in
Objective-C, such as by specifying a parameter to be a variable, that
method must be marked #nonobjc.
To summarize, use #objc when you want to expose a Swift attribute to Objective-C without a namespace . Use #nonobjc if you want to keep the attribute available and accessible only in Swift code.
(Addendum/additional official details to #bontoJR well summarizing answer)
From the Swift Language Reference - Attributes [emphasis mine]:
objc
Apply this attribute to any declaration that can be represented in
Objective-C — for example, non-nested classes, protocols, nongeneric
enumerations (constrained to integer raw-value types), properties and
methods (including getters and setters) of classes and protocols,
initializers, deinitializers, and subscripts. The objc attribute tells
the compiler that a declaration is available to use in Objective-C
code.
...
nonobjc
Apply this attribute to a method, property, subscript, or initializer
declaration to suppress an implicit objc attribute. The nonobjc
attribute tells the compiler to make the declaration unavailable in
Objective-C code, even though it is possible to represent it in
Objective-C.
...
Here you can find more details in this Swift Documentation : InteractingWithObjective-C
As an answer of your question, overview from attached link is as below.
#objc : You can use 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.
Example : if the name of your Swift class contains a character that isn’t supported by Objective-C, you can provide an alternative name to use in Objective-C.
#nonobjc : It makes a swift declaration unavailable in Objective-C. You can use it to resolve circularity for bridging
methods and to allow overloading of methods for classes imported by
Objective-C.

Objective-C call Swift function

Swift function defined in MySwift.swift File:
func SomeSwift()
{
}
SomeSwift() is not defined in any Swift class, it is just a pure function.
After CMD + B to build the project, open Project-Swift.h, the SomeSwift() isn't show in there.
Does the function in Swift have to be defined in some Swift class? and with #objc marked?
like the following:
#objc class SomeSwift: NSObject {
func SomeSwift()
{
}
}
Referring to Apple Documentation about Using Swift from Objective-C:
A Swift class must be a descendant of an Objective-C class to be
accessible and usable in Objective-C
Means that your class should be #objc class SomeSwift: NSObject (You're right!), but you CANNOT access the whole thing in Swift file:
When you create a Swift class that descends from an Objective-C class,
the class and its members—properties, methods, subscripts, and
initializers—that are compatible with Objective-C are automatically
available from Objective-C. This excludes Swift-only features, such as
those listed here:
Generics
Tuples
Enumerations defined in Swift without Int raw value type
Structures defined in Swift
Top-level functions defined in Swift
Global variables defined in Swift
Typealiases defined in Swift
Swift-style variadics
Nested types
Curried functions
Reference.
So, you cannot use the SomeSwift top-level function.
Even if you tried to add #objc before its declaration, the compiler will tell that:
#objc can only used when with memebers of classes, #objc protocols,
and concrete extensions of classes.
with a suggestion to remove #objc.

Using a function or a type method?

I want to create a Helper.swift file to add some functions/methods that are useful in different parts of my app.
I was wondering what is the best practice (if there is one): create a class and only create type methods or just create functions?
I would generally lean towards using a type methods on an appropriately named type, in order to give your helper methods context and avoid polluting the global namespace.
In Swift, structs are an ideal candidate for this sort of construct:
struct Helper {
static func helpfulMethod() { ... }
}
I also use embedded structs with static constants quite liberally in my top level types in order to group related constants within my code.
In writing custom Swift types, you should generally consider using structs first, and only resort to classes when inheritance, reference semantics (as opposed to the implicit copying with value semantics) or ownership semantics (unowned/weak) are required. In this case, your utility functions will be stateless, and there is no inheritance to speak of, so a struct should really be preferred over a class.
I would argue that in general, the Swift language is moving away from global functions in favour of the implicit namespacing provided by types (and protocols/generics). But it's still largely a matter of style/personal preference, and for something as simple as a utility function it's of little consequence.
It is not necessary to create a class or a struct. You can simply put the functions directly in Helper.swift file. And you dont even need to import this file by writing import statements.
To test it out create a file called helper.swift and just add the following lines of code to the file. No class or struct is required.
import Foundation
func addTwo(x: Int) {
return x+2
}
To use this function in any other file just call the function with the required arguments.
let a = addTwo(9)
I prefer this method because when you call the function then you dont have to call it on an instance of a class/struct. Secondly, it leads to cleaner code as you don't have to make each function a class function or a static function.
I will prefer type method because by this way you can easily differentiate your methods.
Suppose you have 50 to 60 methods in which some methods are for designing purpose, some methods are for calculation purpose and some methods are for getting and posting data on server.
Now in this scenario, if you create all these methods as globally it will become hard to recognise and remember.
Now if you differentiate this methods in some class/struct like below:
Methods which are use for Designing purpose make a DesignHelper class/struct and put all these methods into it as class/static method
Methods which are use for calculation purpose make a MathHelper class/struct and put all these method into it as class/static method
Methods which are use for process data with server make a ConnectionHelper class/struct and put all these method into it as class/static method
By using this way you can easily find out any of the method and it will also help in auto completion.
Thank you.
Class functions through a single class work but generally those functions that are being used throughout your app will reuccur on the same objects. A cleaner way is to define your functions in extensions of the object that will use the function. You could put all your extensions in Helper.swift
e.g.
extension UIColor
{
class func randomColor() -> UIColor
{
var randomRed:CGFloat = CGFloat(drand48())
var randomGreen:CGFloat = CGFloat(drand48())
var randomBlue:CGFloat = CGFloat(drand48())
return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
}
}
with usage like this page.backgroundColor = UIColor.randomColor()
So you can still define your functions as class functions or object functions depending on the usage, but within the extension of the object.
This keeps your code clear so you dont route your calls through the helper throughout your code base. Its clearly defined for the object that will be needing the function. If you find code that does not make sense in an extended function then the function probably needs refactoring into more focused functionaly.
I don't know if it is the best practice but here is how I do it.
First I declare a protocol:
protocol UtilityType { }
Then I extend it (For example a utility function for UIViewController)
extension UtilityType where Self: UIViewController {
func setDefaultTitleAttributes() {
navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName: UIColor.whiteColor()]
}
}
And I use it like this
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setDefaultTitleAttributes()
}
}
extension MyViewController: UtilityType {}
Solution #1:
class Helper {
class func classMethod() {
// TODO: play something
}
}
And call it:
Helper.classMethod()
In Apple doc:
Structures are always copied when they are passed around in your code, and do not use reference counting.
Solution #2:
struct Helper {
static func classMethod() {
// TODO: do something
}
}
And use it:
Helper.classMethod()
I think solution#2 better than solution#1 because it's not increase reference counting.
UPDATED: I tested with playground. See the result below:
Hope this helps!

Auto Injection with typhoon + swift

I'm using typhoon in a swift project, as far as i understand i have to map all injections explicitly in a TyphoonAssembly like this:
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition.injectProperty("cityDao", with:self.coreComponents.cityDao())
definition.injectProperty("rootViewController", with:self.rootViewController())
}
}
this seems hard to manage, and very fragile (when refactoring).
I see that there is support for auto injection (matching by types) here:
https://github.com/appsquickly/Typhoon/wiki/Auto-injection-(Objective-C)
but this is for objetive c.
Does anyone know of a way i can wire up the injection without explicitly registering props with their name as string?
Thanks!
(Typhoon creator here).
Typhoon is a dynamic, introspective dependency injection container , and uses the Objective-C run-time. There are the following limitations, when it comes to Swift:
With Objective-C it avoids magic strings, allowing the use of ordinary IDE refactoring tools, however in Swift selectors are magic strings.
The Objective-C runtime only provides type information for properties, not method or initializer parameters. So only properties can support auto-wiring of any kind (macros, implicit, etc).
There is no annotation or macro system for Swift, (but it does have 1st class functions).
You can instruct Typhoon to auto-wire a property in Swift using the following:
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition.injectProperty("cityDao")
definition.injectProperty("rootViewController")
}
}
. . and this will match by type, just as the auto-wiring Objective-C macros do. However this does not avoid specifying the name of the property to be injected. There is no other way to do this in Swift. :(
Its worth mentioning there are additional limitations when using Typhoon with Swift:
"Pure" Swift classes - not extending a Cocoa base class or declaring the #objc directive - don't support introspection, dynamic dispatch or dynamic method invocation. Typhoon only works with Cocoa classes.
Swift protocols require the #objc directive.
It's possible to use Typhoon's auto-wiring in Swift.
The auto-wiring in ObjC is like:
#property (nonatomic, strong) InjectedClass(ViewController) rootViewController;
We can survey the definition of the macro, InjectedClass
#define InjectedProtocol(aProtocol) TyphoonInjectedObject<aProtocol>*
#define InjectedClass(aClass) aClass<TyphoonInjectedProtocol>*
Thus, the auto-wiring in Swift is like
var rootViewController: (ViewController & TyphoonInjectedProtocol)?

Resources