swift method_exchangeImplementations not work - swift

swift code is below:
func swizzleMethod()
{
let method:Method = class_getInstanceMethod(object_getClass(self), Selector("function1"))
self.function1()
let swizzledMethod:Method = class_getInstanceMethod(object_getClass(self), Selector("function2"))
method_exchangeImplementations(method, swizzledMethod)
self.function1()
}
func function1()
{
print("function1 log")
}
func function2()
{
print("function2 log")
}
it logs:
function1 log
function1 log
/////
my environment is swift based project, xcode7.2
This always run into the funtion1 method body, so I think it exchanged failed, this two method is in the same class, anyone know why?

I get the answer, add "dynamic" keyword in front of method name!!!
like this:
dynamic func function1()
{
print("function1 log")
}
dynamic func function2()
{
print("function2 log")
}
Reason:
Swift optimizes code to call direct memory addresses instead of looking up the method location at runtime as in Objective-C. so we need tell the code run treat it as Objective-C code.
Answer Detail:
Method swizzling is a technique that substitutes one method implementation for another. If you're not familiar with swizzling, check out this blog post. Swift optimizes code to call direct memory addresses instead of looking up the method location at runtime as in Objective-C. So by default swizzling doesn’t work in Swift classes unless we:
1. Disable this optimization with the dynamic keyword. This is the preferred choice, and the choice that makes the most sense if the codebase is entirely in Swift.
2. Extend NSObject. Never do this only for method swizzling (use dynamic instead). It’s useful to know that method swizzling will work in already existing classes that have NSObject as their base class, but we're better off selectively choosing methods with dynamic .
3. Use the #objc annotation on the method being swizzled. This is appropriate if the method we would like to swizzle also needs to be exposed to Objective-C code at the same time.
thanks to the article: 15 Tips to Become a Better Swift Developer

Related

Uses of available in Swift

I've going through a Ray Wenderlich tutorial for MVVM and in the view it has
#available(*, unavailable)
public required init?(coder: NSCoder) {
fatalError("init?(coder:) is not supported")
}
I understand providing the required init, but I cannot follow why there is #available(*, unavailable).
The *indicates that availability on all platforms - surely we had that already? Aren't we then marking it as unavailable for all platforms - in this case won't the fatalError never be executed?
I've looked at the Swift guide https://docs.swift.org/swift-book/ReferenceManual/Attributes.html and still don't understand this
From the link you have provided,
The unavailable argument indicates that the declaration isn’t available on the specified platform. This argument can’t be used when specifying Swift version availability.
So essentially you are saying that this initialiser is unavailable on all platforms, which makes sense, as this initialiser is not implemented.
By adding this attribute, you make Swift issue an error when you try to use the initialiser, hence preventing people from calling it accidentally:
It is sometimes handy to make a piece of code unavailable without actually deleting it. Two use cases come to mind:
• A subclass making methods of the superclass unavailable. •
Legacy code that we need to keep in the source to keep supporting old
versions or documentation.
In such cases we can use Swift's available declaration attribute to tell the compiler that code using the marked object or function should not compile.
For example, if you have to subclass NSObject into something that has a stored constant which needs to be passed at initialization, and don't want to allow consumers to call init because it doesn't make sense to set a default value for the constant, you can make init unavailable to its consumers:
class Dummy: NSObject {
let foo: String
init(foo: String) {
self.foo = foo
}
#available(*, unavailable)
override init() {
fatalError()
}
}
NOTE
Unfortunately, as of 2.2, this kind of availability declaration is not converted into an Objective-C attribute, so Objective-C consumers will still see the methods and classes as available.

What's the mechanics behind extension's methods overriding with '#objc' attribute?

Kind of nerd question. It's unclear to me, what exactly makes this code works:
class Shape { }
extension Shape {
#objc func redraw() {
print("from ext")
}
}
class Circle: Shape { }
class Line: Shape {
override func redraw() { // Compiler error: Declarations from extensions cannot be overridden yet
print("from subclass")
}
}
let line = Line()
let shape:Shape = line
let circle = Circle()
line.redraw() //from subclass
circle.redraw() //from ext
shape.redraw() //from subclass
If I omit #objc keyword in extension, the code won't compile - it's expected behaviour since methods in extension use static method dispatch -> cannot be overridden.
But why adding #objc makes it work? According to documentation and most articles, all is #objc doing is making things visible to Objective-c runtime. To change method dispatch type there is a special keyword - dynamic. But seems it is not necessary here!
Help me figure out, why is adding #objc (and omitting dynamic) makes such things possible.
Extensions,
as the name already says, are supposed to extend/add/include methods
to an existing implementation, making them one of the most beautiful
things about Objective-C, and now Swift, since you can add code to a
class or framework you do not own. Therefore, it makes sense that
you’re not supposed to “replace” code in extensions, conceptually
speaking.
That’s why the compiler complains when you try to do it.
Also Check out this answer.
however this seems to be a support issue too, as swift compiler simply throw this error:
overriding non-#objc declarations from extensions is not supported.
According to Apple,
Extensions can add new functionality to a type, but they cannot
override existing functionality.
But that is not the case, as we are overriding from the extension not vice versa,
which takes us back to the declaration of extension.
Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) Here.
Going back to the legacy topic swift compiler vs Objc compiler,
Dynamic dispatch vs. Static dispatch .
And there is no official documentation from apple on why this is not supported from the swift compiler or if they have any future plans to fix this or consider it an issue at all.
However, there’s no such thing as Swift dynamic dispatch; we only have
the Objective-C runtime’s dynamic dispatch. That means you can’t have
just dynamic and you must write #objc dynamic. So this is effectively
the same situation as before, just made explicit.
And here is a great article talking about this topic deeply.

Why must Protocol defaults be implemented via Extensions in Swift?

In Swift, you cannot define default implementations of functions or properties in the Protocol definition itself, i.e.:
protocol Container {
//These are fine
associatedtype Item
mutating func append(_ item: Item)
var count: Int { get set }
subscript(i: Int) -> Item { get }
//These are not fine
var defaultValue: Int = 10
mutating func messWithCount(){
self.count *= 10
}
}
extension Container {
//This is fine though
mutating func messWithCount(){
self.count *= 10
}
}
But you could do so via the Extensions (although Extensions do not support stored properties, they support functions and computed ones - although the stored property issue can be worked around).
What is the explanation behind this? As an add along, what is the explanation for optional func being only implementable if we mark both the Protocol and the func as #objc and hence rendering it unusable for Structs/Enums (which are Value not Reference based)?
EDIT: Added in Extension example
The #optional directive is an Objective-C only directive and has not been translated to Swift. This doesn't mean that you can't use it in Swift, but that you have to expose your Swift code to Objective-C first with he #objc attribute.
Note that exposing to Obj-C will only make the protocol available to types that are in both Swift and Obj-C, this excludes for example Structs as they are only available in Swift!
To answer your first question, Protocols are here to define and not implement:
A protocol defines a blueprint of methods, properties, and other requirements [...]
And the implementation should thus be supplied by the class/stuct/enum that conforms to it:
The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements
This definition really applies to Protocols we use in our daily lives as well. Take for example the protocol to write a Paper:
The PaperProtocol defines a paper as a document with the following non-nil variables:
Introduction
Chapters
Conclusion
What the introduction, chapters and conclusion contain are up to the one implementing them (the writer) and not the protocol.
When we look at the definition of Extensions, we can see that they are here to add (implement) new functionalities:
Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code.
So extending a protocol (which is allowed) gives you the possibility to add new functionality and hereby give a default implementation of a defined method. Doing so will work as a Swift only alternative to the #optional directive discussed above.
UPDATE:
While giving a default implementation to a protocol function in Switch does make it "optional", it is fundamentally not the same as using the #optional directive in Objective-C.
In Objective-C, an optional method that is not implemented has no implementation at all so calling it would result in a crash as it does not exist. One would thus have to check if it exists before calling it, in opposition to Swift with an extension default where you can call it safely as a default implementation exists.
An optional in Obj-C would be used like this:
NSString *thisSegmentTitle;
// Verify that the optional method has been implemented
if ([self.dataSource respondsToSelector:#selector(titleForSegmentAtIndex:)]) {
// Call it
thisSegmentTitle = [self.dataSource titleForSegmentAtIndex:index];
} else {
// Do something as fallback
}
Where it's Swift counterpart with extension default would be:
let thisSegmentTitle = self.dataSource.titleForSegmentAtIndex(index)

There is a code involves the Delegate Up, I hope I understand it right

Delegation is a new concept for me. To my understanding, it asks someone else to do some job for me. I then, delegate some tasks to him.
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
class Bicycle: Vehicle {
override init() {
super.init() //# Delegate up
numberOfWheels = 2
}
}
The code super.init() is a delegate up action in class initialization. The subclass initializer calls the initializer of the superclass first. The superclass' default initializer assigning the integer 0 to the variable numberOfWheels. This is Phase one initialization. After that, the overriding action of the subclass' initializer further customizes the variable by numberOfWheels = 2.
Question Is there any incorrectness of my understanding? and I hope the delegate up description I'm used here is correct.
Please correct any error and misunderstandings I have it here. Thanks
What you are depicting here has nothing to do with delegation-pattern at all, it's the concept of inheritance. Your bicycle class is inheriting from Vehicle. Vehicle has already implemented some code, so instead of writing it again you can use the code of the super-class (the class that is inherited from). Your super-class doesn't have a defined initializer, therefore the super.init() wont even do anything. You should read about inheritance and try to understand this concept better.
Here's what delegation does: You are right about the idea of delegation. It allows you to "outsource" some work to another class. This can be achieved with protocols. A delegate has to conform a delegation protocol to ensure that it has the methods you want to call on it. You are using protocols instead of inherited classes here, because you don't care about the implementation of the specific methods, you just want to tell your delegate to handle a situation, it's up to the delegate to know what to do.
Delegation is most commonly used in MVC applications for macOS and iOS. You can read more about delegation in the Apple Documentation. There are also dozens of tutorials like this one on the internet that show how delegation works in practice.

Stubbing methods for unit testing in swift 2

I am finding it difficult to stub methods in structs in swift. I can do it currently using a way that I'll explain below, but it feels wrong to me and would like an opinion on it.
I do not use any third party libraries for stubbing, instead I prefer to override the specific method whose result I need to change. Prior to swift, I would always use classes - so it was easy to subclass and override the method that I needed mocked in my unit test case.
Now most of my constructs are structs as they do not really need to be reference types. But then I cannot override any method in my test cases. I do it currently using protocol extensions as outlined below -
protocol AProtocol {
func a()
func b() // This calls a()
}
extension AProtocol {
func a(){
//Default implementation of a()
}
func b(){
//Default implementation of b() which also calls a()
}
}
struct A:AProtocol {
// Empty. struct A will be used by other classes/structs in the code
}
In my test case
struct TestA:AProtocol {
func a() {
Some mock implementation of a() so that b() can be tested
}
}
So my question is this - There is no real need for struct A to be implemented via a protocol. None of the other classes or structs will ever implement AProtocol. But this is the only way I can mock its methods for unit testing. I think the WWDC session on protocol extensions also showed this way of unit testing, but basically I do not need my struct as an implementation of a protocol.
Is there any other way to stub struct methods in swift (without using any third party libs)? Or a better way to test a struct's methods.
I'm going to be the person that doesn't answer the question and explores whether you really need to do what you ask I'm afraid.
My question is whether you really need mock the struct. For non mutating functions set up the struct and test the return value. For mutating functions check the state afterwards is as you expect.
With structs there shouldn't generally be side effects beyond the modification so there is no need to track exactly what other functions are called.
The bit that may be close enough to an answer to be slightly helpful:
If you really are doing something with side effects outside the struct I would suggest that you make the object that the effects are being done to or on injectable so that with an additional testing only init you can inject an alternate mock object to receive the side effect calls.