How to swizzle Swift.print(items:separator:terminator)
I am looking for ways to swizzle Swift.print
function. Overriding it is not an option, as it may get bypasses if you use Swift.print(:)
The selector does not recognise the identifier:
@objc class func printSwizzle() {
guard let instance = class_getInstanceMethod(self, #selector(print(separator:terminator:))),
let swizzleInstance = class_getInstanceMethod(self, #selector(swizzlePrint(separator:terminator:))) else { return }
method_exchangeImplementations(instance, swizzleInstance)
}
Is that even possible? As swizzling is an obj-c
runtime feature.
ios swift method-swizzling
add a comment |
I am looking for ways to swizzle Swift.print
function. Overriding it is not an option, as it may get bypasses if you use Swift.print(:)
The selector does not recognise the identifier:
@objc class func printSwizzle() {
guard let instance = class_getInstanceMethod(self, #selector(print(separator:terminator:))),
let swizzleInstance = class_getInstanceMethod(self, #selector(swizzlePrint(separator:terminator:))) else { return }
method_exchangeImplementations(instance, swizzleInstance)
}
Is that even possible? As swizzling is an obj-c
runtime feature.
ios swift method-swizzling
For a function to be swizzled, it has to be declared as@dynamic
and marked with@objc
. Swift.print doesn't check any of those conditions.
– Carpsen90
Jan 1 at 8:12
1
To add to whatCarpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)
– Alexander
Jan 1 at 8:28
1
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it
– Alexander
Jan 1 at 8:29
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32
add a comment |
I am looking for ways to swizzle Swift.print
function. Overriding it is not an option, as it may get bypasses if you use Swift.print(:)
The selector does not recognise the identifier:
@objc class func printSwizzle() {
guard let instance = class_getInstanceMethod(self, #selector(print(separator:terminator:))),
let swizzleInstance = class_getInstanceMethod(self, #selector(swizzlePrint(separator:terminator:))) else { return }
method_exchangeImplementations(instance, swizzleInstance)
}
Is that even possible? As swizzling is an obj-c
runtime feature.
ios swift method-swizzling
I am looking for ways to swizzle Swift.print
function. Overriding it is not an option, as it may get bypasses if you use Swift.print(:)
The selector does not recognise the identifier:
@objc class func printSwizzle() {
guard let instance = class_getInstanceMethod(self, #selector(print(separator:terminator:))),
let swizzleInstance = class_getInstanceMethod(self, #selector(swizzlePrint(separator:terminator:))) else { return }
method_exchangeImplementations(instance, swizzleInstance)
}
Is that even possible? As swizzling is an obj-c
runtime feature.
ios swift method-swizzling
ios swift method-swizzling
edited Jan 1 at 8:42
JJJ
29.2k147591
29.2k147591
asked Jan 1 at 7:07
Tal ZionTal Zion
3,0812244
3,0812244
For a function to be swizzled, it has to be declared as@dynamic
and marked with@objc
. Swift.print doesn't check any of those conditions.
– Carpsen90
Jan 1 at 8:12
1
To add to whatCarpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)
– Alexander
Jan 1 at 8:28
1
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it
– Alexander
Jan 1 at 8:29
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32
add a comment |
For a function to be swizzled, it has to be declared as@dynamic
and marked with@objc
. Swift.print doesn't check any of those conditions.
– Carpsen90
Jan 1 at 8:12
1
To add to whatCarpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)
– Alexander
Jan 1 at 8:28
1
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it
– Alexander
Jan 1 at 8:29
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32
For a function to be swizzled, it has to be declared as
@dynamic
and marked with @objc
. Swift.print doesn't check any of those conditions.– Carpsen90
Jan 1 at 8:12
For a function to be swizzled, it has to be declared as
@dynamic
and marked with @objc
. Swift.print doesn't check any of those conditions.– Carpsen90
Jan 1 at 8:12
1
1
To add to what
Carpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)– Alexander
Jan 1 at 8:28
To add to what
Carpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)– Alexander
Jan 1 at 8:28
1
1
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it– Alexander
Jan 1 at 8:29
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it– Alexander
Jan 1 at 8:29
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32
add a comment |
2 Answers
2
active
oldest
votes
Method swizzling is an Objective-C feature that enables you to exchange implementation of a method at runtime. For that, you need an @objc
object that inherits from NSObject
. And you need a method.
Swift.print
is not a method. It's a function declared in the Swift
module. We can say it's global but it's not really global. It's defined inside module Swift
which is imported automatically to every Swift code, therefore you can use it without the Swift.
prefix.
In summary, there is no way to swizzle Swift.print
.
What you can do is to hide that function using your own implementation, that is, if you declare a function with the same name in your own module, then when print
is used, the compiler will prefer your function instead because functions in the current module are preferred over functions in other modules (including Swift.
module).
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "($0)" }.joined(separator: separator)
Swift.print(output, terminator: terminator)
}
You can any logic you want in there.
It's actually very common to use this to remove logging from production, e.g.:
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "n") {}
#endif
See Remove println() for release version iOS Swift for more details.
Essentially, you could hide the whole Swift
module by redeclaring it inside your module, e.g. as an enum
, therefore disabling calls to Swift.print
:
enum Swift {
public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
// do something
}
}
However, I would generally advise against this because it will be hard to solve any naming conflicts with the standard library inside the Swift.
module.
In general, I would advise to implement your custom logging system and enforce its usage by other means, e.g. code reviews or linting rules (e.g. swiftlint).
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
add a comment |
Adding to the comments by Alexander and Carpsen90
Method Swizzling is an Objective-C runtime feature and it is inherently not available in Swift as Swift is not a dynamic language. However, you can have a global function as in this SO Post. Below is the updated code for Swift 4.2.
But unfortunately, it calls the original Swift.print
function if the function name is print
. So I changed the function name to logs
public func logs(items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
Another Possible option is to put it into a protocol
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print("****" + output)
}
}
Usage
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
But this way the function ceases to be a global function and while using print
you have to select the correct method
Output
*****Hello World
1
You didn't have correct external parameter names. It would have to beprint(_ items: ...)
notprint(items: ...)
. That's why your method did not get called.
– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53993673%2fhow-to-swizzle-swift-printitemsseparatorterminator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Method swizzling is an Objective-C feature that enables you to exchange implementation of a method at runtime. For that, you need an @objc
object that inherits from NSObject
. And you need a method.
Swift.print
is not a method. It's a function declared in the Swift
module. We can say it's global but it's not really global. It's defined inside module Swift
which is imported automatically to every Swift code, therefore you can use it without the Swift.
prefix.
In summary, there is no way to swizzle Swift.print
.
What you can do is to hide that function using your own implementation, that is, if you declare a function with the same name in your own module, then when print
is used, the compiler will prefer your function instead because functions in the current module are preferred over functions in other modules (including Swift.
module).
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "($0)" }.joined(separator: separator)
Swift.print(output, terminator: terminator)
}
You can any logic you want in there.
It's actually very common to use this to remove logging from production, e.g.:
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "n") {}
#endif
See Remove println() for release version iOS Swift for more details.
Essentially, you could hide the whole Swift
module by redeclaring it inside your module, e.g. as an enum
, therefore disabling calls to Swift.print
:
enum Swift {
public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
// do something
}
}
However, I would generally advise against this because it will be hard to solve any naming conflicts with the standard library inside the Swift.
module.
In general, I would advise to implement your custom logging system and enforce its usage by other means, e.g. code reviews or linting rules (e.g. swiftlint).
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
add a comment |
Method swizzling is an Objective-C feature that enables you to exchange implementation of a method at runtime. For that, you need an @objc
object that inherits from NSObject
. And you need a method.
Swift.print
is not a method. It's a function declared in the Swift
module. We can say it's global but it's not really global. It's defined inside module Swift
which is imported automatically to every Swift code, therefore you can use it without the Swift.
prefix.
In summary, there is no way to swizzle Swift.print
.
What you can do is to hide that function using your own implementation, that is, if you declare a function with the same name in your own module, then when print
is used, the compiler will prefer your function instead because functions in the current module are preferred over functions in other modules (including Swift.
module).
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "($0)" }.joined(separator: separator)
Swift.print(output, terminator: terminator)
}
You can any logic you want in there.
It's actually very common to use this to remove logging from production, e.g.:
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "n") {}
#endif
See Remove println() for release version iOS Swift for more details.
Essentially, you could hide the whole Swift
module by redeclaring it inside your module, e.g. as an enum
, therefore disabling calls to Swift.print
:
enum Swift {
public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
// do something
}
}
However, I would generally advise against this because it will be hard to solve any naming conflicts with the standard library inside the Swift.
module.
In general, I would advise to implement your custom logging system and enforce its usage by other means, e.g. code reviews or linting rules (e.g. swiftlint).
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
add a comment |
Method swizzling is an Objective-C feature that enables you to exchange implementation of a method at runtime. For that, you need an @objc
object that inherits from NSObject
. And you need a method.
Swift.print
is not a method. It's a function declared in the Swift
module. We can say it's global but it's not really global. It's defined inside module Swift
which is imported automatically to every Swift code, therefore you can use it without the Swift.
prefix.
In summary, there is no way to swizzle Swift.print
.
What you can do is to hide that function using your own implementation, that is, if you declare a function with the same name in your own module, then when print
is used, the compiler will prefer your function instead because functions in the current module are preferred over functions in other modules (including Swift.
module).
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "($0)" }.joined(separator: separator)
Swift.print(output, terminator: terminator)
}
You can any logic you want in there.
It's actually very common to use this to remove logging from production, e.g.:
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "n") {}
#endif
See Remove println() for release version iOS Swift for more details.
Essentially, you could hide the whole Swift
module by redeclaring it inside your module, e.g. as an enum
, therefore disabling calls to Swift.print
:
enum Swift {
public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
// do something
}
}
However, I would generally advise against this because it will be hard to solve any naming conflicts with the standard library inside the Swift.
module.
In general, I would advise to implement your custom logging system and enforce its usage by other means, e.g. code reviews or linting rules (e.g. swiftlint).
Method swizzling is an Objective-C feature that enables you to exchange implementation of a method at runtime. For that, you need an @objc
object that inherits from NSObject
. And you need a method.
Swift.print
is not a method. It's a function declared in the Swift
module. We can say it's global but it's not really global. It's defined inside module Swift
which is imported automatically to every Swift code, therefore you can use it without the Swift.
prefix.
In summary, there is no way to swizzle Swift.print
.
What you can do is to hide that function using your own implementation, that is, if you declare a function with the same name in your own module, then when print
is used, the compiler will prefer your function instead because functions in the current module are preferred over functions in other modules (including Swift.
module).
public func print(_ items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "($0)" }.joined(separator: separator)
Swift.print(output, terminator: terminator)
}
You can any logic you want in there.
It's actually very common to use this to remove logging from production, e.g.:
#if !DEBUG
func print(_ items: Any..., separator: String = " ", terminator: String = "n") {}
func debugPrint(_ items: Any..., separator: String = " ", terminator: String = "n") {}
#endif
See Remove println() for release version iOS Swift for more details.
Essentially, you could hide the whole Swift
module by redeclaring it inside your module, e.g. as an enum
, therefore disabling calls to Swift.print
:
enum Swift {
public static func print(_ items: Any..., separator: String = " ", terminator: String = " ") {
// do something
}
}
However, I would generally advise against this because it will be hard to solve any naming conflicts with the standard library inside the Swift.
module.
In general, I would advise to implement your custom logging system and enforce its usage by other means, e.g. code reviews or linting rules (e.g. swiftlint).
edited Jan 1 at 19:35
answered Jan 1 at 19:13
SulthanSulthan
96.9k16157202
96.9k16157202
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
add a comment |
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
But he says in his question “Overriding it is not an option, as it may get bypasses if you use Swift.print(:)”. So he knows this and rejects it.
– matt
Jan 1 at 19:21
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
@matt Against by better judgement I have updated my answer to solve that.
– Sulthan
Jan 1 at 19:29
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
Thanks, @Sulthan , your solution to the problem is interesting.
– Tal Zion
Jan 2 at 6:23
add a comment |
Adding to the comments by Alexander and Carpsen90
Method Swizzling is an Objective-C runtime feature and it is inherently not available in Swift as Swift is not a dynamic language. However, you can have a global function as in this SO Post. Below is the updated code for Swift 4.2.
But unfortunately, it calls the original Swift.print
function if the function name is print
. So I changed the function name to logs
public func logs(items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
Another Possible option is to put it into a protocol
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print("****" + output)
}
}
Usage
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
But this way the function ceases to be a global function and while using print
you have to select the correct method
Output
*****Hello World
1
You didn't have correct external parameter names. It would have to beprint(_ items: ...)
notprint(items: ...)
. That's why your method did not get called.
– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
add a comment |
Adding to the comments by Alexander and Carpsen90
Method Swizzling is an Objective-C runtime feature and it is inherently not available in Swift as Swift is not a dynamic language. However, you can have a global function as in this SO Post. Below is the updated code for Swift 4.2.
But unfortunately, it calls the original Swift.print
function if the function name is print
. So I changed the function name to logs
public func logs(items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
Another Possible option is to put it into a protocol
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print("****" + output)
}
}
Usage
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
But this way the function ceases to be a global function and while using print
you have to select the correct method
Output
*****Hello World
1
You didn't have correct external parameter names. It would have to beprint(_ items: ...)
notprint(items: ...)
. That's why your method did not get called.
– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
add a comment |
Adding to the comments by Alexander and Carpsen90
Method Swizzling is an Objective-C runtime feature and it is inherently not available in Swift as Swift is not a dynamic language. However, you can have a global function as in this SO Post. Below is the updated code for Swift 4.2.
But unfortunately, it calls the original Swift.print
function if the function name is print
. So I changed the function name to logs
public func logs(items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
Another Possible option is to put it into a protocol
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print("****" + output)
}
}
Usage
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
But this way the function ceases to be a global function and while using print
you have to select the correct method
Output
*****Hello World
Adding to the comments by Alexander and Carpsen90
Method Swizzling is an Objective-C runtime feature and it is inherently not available in Swift as Swift is not a dynamic language. However, you can have a global function as in this SO Post. Below is the updated code for Swift 4.2.
But unfortunately, it calls the original Swift.print
function if the function name is print
. So I changed the function name to logs
public func logs(items: Any..., separator: String = " ", terminator: String = "n") {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print(output, terminator: terminator)
}
Another Possible option is to put it into a protocol
public protocol CustomPrintable {
func print(_ items: Any...)
}
extension CustomPrintable {
func print(_ items: Any...) {
let output = items.map { "*($0)"}.joined(separator: " ")
Swift.print("****" + output)
}
}
Usage
class SampleClass : CustomPrintable {
func printValue() {
print ("Hello World")
}
}
But this way the function ceases to be a global function and while using print
you have to select the correct method
Output
*****Hello World
edited Jan 1 at 20:59
Tal Zion
3,0812244
3,0812244
answered Jan 1 at 16:18
Md. Ibrahim HassanMd. Ibrahim Hassan
3,60211130
3,60211130
1
You didn't have correct external parameter names. It would have to beprint(_ items: ...)
notprint(items: ...)
. That's why your method did not get called.
– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
add a comment |
1
You didn't have correct external parameter names. It would have to beprint(_ items: ...)
notprint(items: ...)
. That's why your method did not get called.
– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
1
1
You didn't have correct external parameter names. It would have to be
print(_ items: ...)
not print(items: ...)
. That's why your method did not get called.– Sulthan
Jan 2 at 8:08
You didn't have correct external parameter names. It would have to be
print(_ items: ...)
not print(items: ...)
. That's why your method did not get called.– Sulthan
Jan 2 at 8:08
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
@Sulthan Thanks for pointing it out, I made the change but still the function call goes to the Swift.print function
– Md. Ibrahim Hassan
Jan 2 at 16:17
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53993673%2fhow-to-swizzle-swift-printitemsseparatorterminator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
For a function to be swizzled, it has to be declared as
@dynamic
and marked with@objc
. Swift.print doesn't check any of those conditions.– Carpsen90
Jan 1 at 8:12
1
To add to what
Carpsen90
said, swizzling only works because in ObjC land, there is one central place that all method calls jump through, which is the ObjC runtime. That's great because it can let you do crazy stuff like intercepting and forwarding messages, swizzling method implementations, etc. On the down side, it can hurt performance pretty drastically. Swift function calls can be much more aggressively optimized (e.g. for small enough functions, calls can be replaced with an inline "copy", saving cost of a function call)– Alexander
Jan 1 at 8:28
1
Swift.print
is a global function, which doesn't belong to any class or object. It has no relation to the ObjC runtime, so you can't use the ObjC runtime to try to modify it– Alexander
Jan 1 at 8:29
Explain what you are really trying to do.
– matt
Jan 1 at 19:20
Thank you @matt , I was after swizzling the print function but as we all know and after everyone commented, this is not possible. All the answers are great for the community to learn. This is what I do now anyway, but wanted to avoid it. Cheers
– Tal Zion
Jan 1 at 19:32