Manu Gupta
Manu Gupta

Reputation: 1759

How to swizzle init method of NSURLConnection class

I want to swizzle init init method of NSURLConnection class and i have tried this code but it doesn't seem to work for me

extension NSURLConnection{
public override class func initialize() {
    struct Static {
        static var token: dispatch_once_t = 0
    }
    dispatch_once(&Static.token) {
        let originalSelector = Selector("init:delegate:startImmediately:")
        let swizzledSelector = Selector("my_init:delegate:startImmediately:")

        let originalMethod = class_getInstanceMethod(self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

        let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

// MARK: - Method Swizzling
func my_init(request: NSURLRequest, delegate: AnyObject?, startImmediately: Bool){
 print("Inside Swizzled Method")
}
}

And here is the request which i am initiating from my view controller

let testPoint: String = "www.google.com"
    guard let url = NSURL(string: testPoint) else {
        print("Error: cannot create URL")
        return
    }
    let urlRequest = NSURLRequest(URL: url)
    let conn = NSURLConnection(request: urlRequest, delegate: self, startImmediately: true)

Upvotes: 0

Views: 1591

Answers (2)

Michał Ciuba
Michał Ciuba

Reputation: 7944

I think there are two things that have to be fixed:

As mentioned in this answer, you should use Objective-C method signature in originalSelector:

`let originalSelector = Selector("initWithRequest:delegate:startImmediately:")`

You don't return anything from my_init method. You should return the same type as the method being swizzled, in this case NSURLConnection.

func my_init(request: NSURLRequest, delegate: AnyObject?, startImmediately: Bool) -> NSURLConnection? {
    print("Inside Swizzled Method")
    //call the original initializer
    return my_init( request, delegate: delegate, startImmediately: startImmediately)
}

You can see that my_init is called in the swizzled method. In the runtime, it will call the original initWithRequest:delegate:startImmediately as the methods will have been already swapped at this point.

Last but not least, NSURLConnection is deprecated in iOS 9. It is highly recommended to use NSURLSession instead, as it's more modern and has more useful features.

Upvotes: 0

yoninja
yoninja

Reputation: 1962

extension NSURLConnection{
public override class func initialize() {
    struct Static {
        static var token: dispatch_once_t = 0
    }

    if self !== NSURLConnection.self {
        return
    }

    dispatch_once(&Static.token) {
        let originalSelector = Selector("initWithRequest:delegate:startImmediately:")
        let swizzledSelector = Selector("initWithTest:delegate:startImmediately:")

        let originalMethod = class_getInstanceMethod(self, originalSelector)
        let swizzledMethod = class_getInstanceMethod(self, swizzledSelector)

        let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))

        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

// MARK: - Method Swizzling
convenience init(test: NSURLRequest, delegate: AnyObject?, startImmediately: Bool){
    print("Inside Swizzled Method")
    self.init()
}
}

Upvotes: 2

Related Questions