2

I am trying to swizzle a Swift function that contains a StaticString parameter.

Here is what I tried:

let method = class_getClassMethod(self, original1)

class ABC {
  public static func updateABC(context: Int, str: StaticString) {
  }
}

However, this doesn't work, if I change the type of str to String, we can swizzle properly, anyone has chance to swizzle a function with StaticString type parameter could help out?

Thanks

Oliver Hu
  • 148
  • 7
  • 2
    why you want to do this? – Bryan Chen Nov 17 '15 at 00:27
  • for example - Swizzle swift's assertFailure @BryanChen – Oliver Hu Nov 17 '15 at 00:41
  • so the next question is... why you need to swizzle `assertFailure`? can't you just have a method `myAssertFailure` and call it instead? method swizzle is unique to ObjC and I don't think you should use it for Swift project because it will not always work as you expected. Swift compiler may do aggressive inlining which will pick the original implementation instead of the swizzled one. – Bryan Chen Nov 17 '15 at 00:48
  • I agree with @BryanChen. Swift is meant to be safe and even in Swift 2, reflection capabilities are read-only (as they should be). Doing any sort of swizzling in Swift using the obj-c runtime is bad idea; not every type will support it (native swift types like structs, enums, etc) – barndog Nov 17 '15 at 00:50
  • Coming from Objective-C myself, I still find that writing Swift code requires a shift in thinking about how you design your class, structures, etc. While there are some cases to be made for having dynamic introspection, there's plenty of good reasons not to. I would go so far as to say that everything that can be done in Objective-C can be done in Swift, it's just a matter of how you design your classes. Take ReactiveCocoa for example, it primarily relied on KVO for observing changes which Swift doesn't have. Now they have a new mechanism, mutable and immutable wrappers on properties. – barndog Nov 17 '15 at 00:53
  • I do agree Swizzling itself is not a good coding practice at all for any application code. But it is very essential for some infrastructure code to work. For example, you want to inject some code before sending the action to a button target. You would never want to provide a subclass of UIButton and force people to use that since they may want to use some other open source UIButton subclasses. – Oliver Hu Nov 17 '15 at 01:23

1 Answers1

1

StaticString is a value type so it has no Objective-C representation. Therefore it–and the declaration you use it in–are not exposed to Objective-C code or registered with the Objective-C runtime. String, on the other hand, is Objective-C compatible (it bridges to NSString) and so the declaration is Objective-C compatible.

If you're going to swizzle a method, you need to mark it with dynamic to let the compiler know that it should always route calls through the Objective-C runtime, even in optimized code. Marking a function with dynamic will also cause the compiler to emit an error if your function is not Objective-C compatible, which could help you diagnose issues.

Jack Lawrence
  • 10,664
  • 1
  • 47
  • 61
  • Thanks! This makes sense. So when you said the declaration is not registered with the objc runtime, how that function works then, like C++ vTable lookup? Any other cases that Swift/Objc methods are not bound to objc runtime? – Oliver Hu Nov 17 '15 at 09:10
  • @OliverHu Great question. There are several different ways Swift method dispatch can occur, and it's up to the compiler/optimizer to decide (unless you use `dynamic`). For example in some cases it's like a vtable, in other cases the optimizer might directly inline the implementation of the method. All swift structs and enums use static dispatch. For pure swift classes–Swift classes that don't inherit from any Objective-C class–the compiler may also choose not to register the class with the Objective-C runtime. – Jack Lawrence Nov 17 '15 at 23:06