To provide a fallback language for NSLocalizedString, I'm using this #undef and #define in Objective-C:
#undef NSLocalizedString
#define NSLocalizedString(key, comment) #"NSLocalizedString has been replaced";
This works perfectly well if called from Objective-C, but if called from Swift, the new definition of NSLocalizedString is ignored. (bridging header is configured correctly and works)
Is this possible in Swift, and if so, how?
Note: the real example is here on Github, also see SO answer here
You can do this for NSObject subclasses like this
extension NSObject {
func NSLocalizedString(key: String, comment: String) -> String {
return "yes we have localized an NSObject"
}
}
What about AnyObject? In this case, you would have to be aware of and conform to the FallbackLanguage protocol in your AnyObject subclass
protocol FallbackLanguage: class {}
// add default implementations
extension FallbackLanguage {
func NSLocalizedString(key: String, comment: String) -> String {
return "yes we have localized AnyObject via FallbackLanguage protocol"
}
}
Notes
These two solutions can both be in your project without any issues.
If you're calling NSLocalizedString outside of a class instance, you're out of luck.
You will have to do a global function... the other options will cause all sort of problems, such as retrain cycles, or classes classes witch do not inherit from NSObject(that is only subset of the problems) - this will not work at all. yes global function usually are big no! but that is the only way to "override" global function. ,
Here is a code I use in production, we had few thousands of string, at some point we had to make our app dynamically localized - and this is what we did.
// Global functions for lagacy code
func NSLocalizedString(_ key: String, comment: String) -> String {
return key.localized()
}
func NSLocalizedStringInTable(key: String, tableName: String ) -> String {
return key.localized(using: tableName)
}
Related
Ready to use example to test in Playgrounds:
import Foundation
class Demo {
let selector = #selector(someFunc(_:))
func someFunc(_ word: String) {
// Do something
}
func someFunc(_ number: Int) {
// Do something
}
}
I'm getting an Ambiguous use of 'someFunc' error.
I have tried this answer and getting something like:
let selector = #selector(someFunc(_:) as (String) -> Void)
But still getting the same result.
Any hints on how to solve this?
Short answer: it can't be done.
Long explanation: when you want to use a #selector, the methods need to be exposed to Objective-C, so your code becomes:
#objc func someFunc(_ word: String) {
// Do something
}
#objc func someFunc(_ number: Int) {
// Do something
}
Thanks to the #objc annotation, they are now exposed to Objective-C and an compatible thunk is generated. Objective-C can use it to call the Swift methods.
In Objective-C we don't call a method directly but instead we try to send a message using objc_msgSend: the compiler is not able to understand that those method are different, since the generated signature is the same, so it won't compile. You will face the error:
Method 'someFunc' with Objective-C selector 'someFunc:' conflicts with previous declaration with the same Objective-C selector.
The only way to fix it is to have different signatures, changing one or both of them.
The selector is obviously ambiguous, neither methods have external parameter names. Remove the empty external parameters to solve this:
#objc func someFunc(word: String) {
// Do something
}
#objc func someFunc(number: Int) {
// Do something
}
After that, you should specify a selector with the parameter name:
#selector(someFunc(word:))
or
#selector(someFunc(number:))
Both this declaration
protocol SomeProtocol : AnyObject {
}
and this declaration
protocol SomeProtocol : class {
}
seem to make it so that only classes can conform to this protocol (i.e. that the instances of the protocol are references to objects), and have no other effects.
Is there any difference between them? Should one be preferred over the other? If not, why is there two ways to do the same thing?
I am using the latest released Xcode 6.3.1.
This was answered by an official Swift developer (Slava_Pestov) on the Swift forums. Here is the summary:
You should use AnyObject (protocol SomeProtocol: AnyObject).
AnyObject and class are equivalent. There is no difference.
class will eventually be deprecated.
Regarding the answer https://forums.swift.org/t/class-only-protocols-class-vs-anyobject/11507/4, this answer is deprecated. These words are the same now.
DEPRECATED
Update: After consulting with the powers that be, the two definitions are supposed to be equivalent, with AnyObject being used as a stand-in while class was being finished. In the future the latter will obviate the former but, for now, they do present a few minor differences.
The difference lies in the semantics of #objc declarations. With AnyObject, the expectation is that conforming classes may or may not be proper Objective-C objects, but the language treats them as such anyway (in that you lose static dispatch sometimes). The takeaway from this is that you can treat an AnyObject et al. protocol constraint as a way to ask for #objc member functions as shown in the example in documentation for AnyObject in the STL:
import Foundation
class C {
#objc func getCValue() -> Int { return 42 }
}
// If x has a method #objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: AnyObject) -> Int? {
if let f: ()->Int = x.getCValue { // <===
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: AnyObject) -> Int? {
return x.getCValue?() // <===
}
// An implementation that assumes the required method is present
func getCValue3(x: AnyObject) -> Int { // <===
return x.getCValue() // x.getCValue is implicitly unwrapped. // <===
}
The same example falls over immediately if you change that to a class-deriving protocol:
import Foundation
protocol SomeClass : class {}
class C : SomeClass {
#objc func getCValue() -> Int { return 42 }
}
// If x has a method #objc getValue()->Int, call it and
// return the result. Otherwise, return nil.
func getCValue1(x: SomeClass) -> Int? {
if let f: ()->Int = x.getCValue { // <=== SomeClass has no member 'getCValue'
return f()
}
return nil
}
// A more idiomatic implementation using "optional chaining"
func getCValue2(x: SomeClass) -> Int? {
return x.getCValue?() // <=== SomeClass has no member 'getCValue'
}
// An implementation that assumes the required method is present
func getCValue3(x: SomeClass) -> Int { // <===
return x.getCValue() // <=== SomeClass has no member 'getCValue'
}
So it seems class is a more conservative version of AnyObject that should be used when you only care about reference semantics and not about dynamic member lookups or Objective-C bridging.
In the Swift programming language guide for protocols, under the Class-Only Protocols section. It only mentioned AnyObject, but not class.
You can limit protocol adoption to class types (and not structures or enumerations) by adding the AnyObject protocol to a protocol’s inheritance list.
protocol SomeClassOnlyProtocol: AnyObject, SomeInheritedProtocol {
// class-only protocol definition goes here
}
For that reason, I will suggest using AnyObject over class for new code or new project. Other than that, I don't see any obvious difference between them.
From 2021, Xcode 12.5, Big Sur OS:
Usage of class is deprecated by apple.
Use AnyObject instead.
Happy Coding.
AnyObject is a protocol to which all classes implicitly conform (source). So I would say there is no difference: you can use either to require class constraint.
If you open the help (alt-click) in Xcode 9 for class in a line such as protocol P: class {}, you will get typealias AnyObject.
Thus, the code compiled (in Swift 4) will be the same whether you constrain the protocol to class or AnyObject.
That said, there is also the question of style and future options — a future Swift version might want to treat class and AnyObject differently in some subtle way, even if that is not the case right now.
(Edit: This has finally happened in Swift 5.4/Xcode 12.5.)
I misspoke before. #MartinR should really answer this, since he's the one who corrected me and provided the correct information.
The real difference is that a protocol with the class qualifier can only be applied to a class, not a struct or enum.
Martin, why don't you answer and the OP can accept your answer?
What protocol do I have to implement to control the way an object is represented within a string interpolation in Swift?
I wan't to specify what get's printed in something like this:
struct A{
}
var a = A()
println("\(a)")
You need to implement the Printable protocol:
This protocol should be adopted by types that wish to customize their
textual representation. This textual representation is used when
objects are written to an OutputStreamType.
protocol Printable {
var description: String { get }
}
There's also the DebugPrintable protocol when it's only for debugging purposes:
This protocol should be adopted by types that wish to customize
their textual representation used for debugging purposes. This
textual representation is used when objects are written to an
OutputStreamType.
protocol DebugPrintable {
var debugDescription: String { get }
}
Documentation (Thanks #MartinR)
Note: As #Antonio and #MartinR mentioned in the comments, this doesn't work in the playground (as of Xcode6 GM anyway); that's a known bug. It does work in compiled apps.
From the Xcode6 GM Release Notes:
In Playgrounds, println() ignores the Printable conformance of
user-defined types. (16562388)
As of Swift 2.0 Printable has now become CustomStringConvertible. Everything stays the same as before, you still need to implement
var description: String { get }
But now its called CustomStringConvertible. And debug is CustomDebugStringConvertible
In Swift 5 Apple introduced Custom String Interpolation.
Suppose you have person struct with two properties name and age.
struct Person {
var name: String
var age: Int
}
If you wanted to add a special string interpolation for that so that we can print persons in descriptive way, we can add an extension to String.StringInterpolation with a new appendInterpolation() method.
extension String.StringInterpolation {
mutating func appendInterpolation(_ person: Person) {
appendInterpolation("My name is \(person.name) and I'm \(person.age) years old.")
}
}
Now If we print the person details like:
let person = Person(name: "Yogendra", age: 28)
print("Person Details: \(person)")
Output will be:
Person Details: My name is Yogendra and I'm 28 years old.
I would like to put an alternative solution here:
The protocol for string interpolation in Swift is StringInterpolationConvertible. That is, any class which implements the protocol, can be constructed from a string interpolation.
Back to the question, to control what is printed out for a String string interpolation of instances of class A, you would need to create a String extension and overload the init(stringInterpolationSegment expr: A) function.
extension String {
init(stringInterpolationSegment expr: A) {
//do custom work here
//for example: self.init(expr.description)
}
}
In case you are looking for a way to remove the annoying "Optional(...)" when interpolating Optional variables, which I think is the main reason why people would want to control how an object gets printed out, just have a look at the pod NoOptionalInterpolation here.
Additional information (edited):
Confirm that overriding description will only work for your own struct/class, but not for existing struct/class such as Int and Optional.
Calling a method from its name (in a String format) can be sometimes useful.
In Swift it is recomended to change behavior and to use closures to do something "dynamically", so for example you can have a dictionary of functions, with the name as the key, and the implementation as the value.
However, sometimes you want to simply know "how to do it", and this is the reason of this question.
So, how to call dynamically a Swift method starting from it's name as string?
In Objective C it was simple:
[self performSelector:NSSelectorFromString(#"aSelector")];
But performSelector is banned in Swift
Is there any alternative?
In Swift, you should use closures and change your approach.
However, if you want to use performSelector to dynamically call a method given only it's String signature, altough it's not supported natively, I've found how to do it.
It is possible to create a C alternative to performSelector that:
works even on native swift classes (non objective-c)
takes a selector from string
However it's not so straightforward to implement a complete version of it, and it's necessary to create the method in C.
in C we have dlsym(), a function that returns a pointer to a function given the char symbol.
Well, reading this interesting post:
http://www.eswick.com/2014/06/inside-swift/
I've learned a lot of interesting things about swift.
Swift instance methods are plain functions with a specific signature, like this
_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
where the "self" value is passed as the last parameter
in short you can call it directly from the c side without any kind of bridging, it is sufficient to rebuild the correct function signature.
In the signature above, there is the name of the project (FirstSwiftTest) and the lenght (14), the name of the class (ASampleClass) and the lenght (12), the name of the function (aTestFunction) and the lenght (13), then other values as the return type ecc ecc. For other details look at the previous link
The function above, is the representation of this:
class ASampleClass
{
func aTestFunction() -> NSString
{
println("called correctly")
return NSString(string: "test")
}
}
Well, on the c side, I was able to create this function
#include <stdio.h>
#include <dlfcn.h>
typedef struct objc_object *id;
id _performMethod(id stringMethod, id onObject)
{
// ...
// here the code (to be created) to translate stringMethod in _TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
// ...
id (*functionImplementation)(id);
*(void **) (&functionImplementation) = dlsym(RTLD_DEFAULT, "_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString");
char *error;
if ((error = dlerror()) != NULL) {
printf("Method not found \n");
} else {
return functionImplementation(onObject); // <--- call the function
}
return NULL
}
And then called it on the swift side
let sampleClassInstance = ASampleClass()
println(_performMethod("aTestFunction", sampleClassInstance))
The function resulted in these statement printed on the log:
called correctly
test
So it should be not so difficult to create a _performMethod() alternative in C that:
creates automatically the function signature (since it seems to have a logic :-)
manages different return value types and parameters
EDIT
In Swift 2 (and maybe in Beta3, I didn't try) It seems that performSelector() is permitted (and you can call it only on NSObject subclasses). Examining the binary, It seems that now Swift creates static functions that can be specifically called by performSelector.
I created this class
class TestClass: NSObject {
func test() -> Void {
print("Hello");
}
}
let test = TestClass()
let aSel : Selector = NSSelectorFromString("test")
test.performSelector(aSel)
and now in the binary I find
000000010026d830 t __TToFC7Perform9TestClass4testfT_T_
At this time, I don't understand well the reasons behind this, but I'll investigate further
You could call a method from a String this way:
let foo = <some NSObject subclass instance>
let selectorName = "name"
foo.perform(Selector(selectorName))
It is available only when your foo class is subclass of NSObject
swift3 version
class MyClass:NSObject
{
required public override init() { print("Hi!") }
public func test(){
print("This is Test")
}
public class func static_test(){
print("This is Static Test")
}
}
if let c: NSObject.Type = NSClassFromString("TestPerformSelector.MyClass") as? NSObject.Type{
let c_tmp = c.init()
c_tmp.perform(Selector("test"))
c.perform(Selector("static_test"))
}
I wish to check if a func exists before I call it. For example:
if let touch: AnyObject = touches.anyObject() {
let location = touch.locationInView(self)
touchMoved(Int(location.x), Int(location.y))
}
I would like to call touchMoved(Int, Int) if it exists. Is it possible?
You can use the optional chaining operator:
This seems to only work with ObjC protocols that have #optional functions defined. Also seems to require a cast to AnyObject:
import Cocoa
#objc protocol SomeRandomProtocol {
#optional func aRandomFunction() -> String
#optional func anotherRandomFunction() -> String
}
class SomeRandomClass : NSObject {
func aRandomFunction() -> String {
return "aRandomFunc"
}
}
var instance = SomeRandomClass()
(instance as AnyObject).aRandomFunction?() //Returns "aRandomFunc"
(instance as AnyObject).anotherRandomFunction?() //Returns nil, as it is not implemented
Whats weird is that in the example above, the protocol "SomeRandomProtocol" is not even declared for "SomeRandomClass"... yet without the protocol definition, the chaining operator gives an error-- in the playground at least. Seems like the compiler needs a prototype of the function declared previously for the ?() operator to work.
Seems like maybe there's some bugs or work to do there.
See the "swift interoperability in depth" session for more info on the optional chaining operator and how it works in this case.