Skip to content

Commit

Permalink
Removed final keyword from SessionManager declaration to allow subcla…
Browse files Browse the repository at this point in the history
…ssing.
  • Loading branch information
cnoon committed Apr 9, 2016
1 parent 34ab394 commit 971e2f8
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,74 @@ enum Router: URLRequestConvertible {
Alamofire.request(Router.ReadUser("mattt")) // GET /users/mattt
```

### SessionDelegate

By default, an Alamofire `Manager` instance creates an internal `SessionDelegate` object to handle all the various types of delegate callbacks that are generated by the underlying `NSURLSession`. The implementations of each delegate method handle the most common use cases for these types of calls abstracting the complexity away from the top-level APIs. However, advanced users may find the need to override the default functionality for various reasons.

#### Override Closures

The first way to customize the `SessionDelegate` behavior is through the use of the override closures. Each closure gives you the ability to override the implementation of the matching `SessionDelegate` API, yet still use the default implementation for all other APIs. This makes it easy to customize subsets of the delegate functionality. Here are a few examples of some of the override closures available:

```swift
/// Overrides default behavior for NSURLSessionDelegate method `URLSession:didReceiveChallenge:completionHandler:`.
public var sessionDidReceiveChallenge: ((NSURLSession, NSURLAuthenticationChallenge) -> (NSURLSessionAuthChallengeDisposition, NSURLCredential?))?

/// Overrides default behavior for NSURLSessionDelegate method `URLSessionDidFinishEventsForBackgroundURLSession:`.
public var sessionDidFinishEventsForBackgroundURLSession: ((NSURLSession) -> Void)?

/// Overrides default behavior for NSURLSessionTaskDelegate method `URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:`.
public var taskWillPerformHTTPRedirection: ((NSURLSession, NSURLSessionTask, NSHTTPURLResponse, NSURLRequest) -> NSURLRequest?)?

/// Overrides default behavior for NSURLSessionDataDelegate method `URLSession:dataTask:willCacheResponse:completionHandler:`.
public var dataTaskWillCacheResponse: ((NSURLSession, NSURLSessionDataTask, NSCachedURLResponse) -> NSCachedURLResponse?)?
```

The following is a short example of how to use the `taskWillPerformHTTPRedirection` to avoid following redirects to any `apple.com` domains.

```swift
let delegate: Alamofire.Manager.SessionDelegate = manager.delegate

delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
var finalRequest = request

if let originalRequest = task.originalRequest where originalRequest.URLString.containsString("apple.com") {
finalRequest = originalRequest
}

return finalRequest
}
```

#### Subclassing

Another way to override the default implementation of the `SessionDelegate` is to subclass it. Subclassing allows you completely customize the behavior of the API or to create a proxy for the API and still use the default implementation. Creating a proxy allows you to log events, emit notifications, provide pre and post hook implementations, etc. Here's a quick example of subclassing the `SessionDelegate` and logging a message when a redirect occurs.

```swift
class LoggingSessionDelegate: Manager.SessionDelegate {
override func URLSession(
session: NSURLSession,
task: NSURLSessionTask,
willPerformHTTPRedirection response: NSHTTPURLResponse,
newRequest request: NSURLRequest,
completionHandler: NSURLRequest? -> Void)
{
print("URLSession will perform HTTP redirection to request: \(request)")

super.URLSession(
session,
task: task,
willPerformHTTPRedirection: response,
newRequest: request,
completionHandler: completionHandler
)
}
}
```

Generally, either the default implementation or the override closures should provide the necessary functionality required. Subclassing should only be used as a last resort.

> It is important to keep in mind that the `subdelegates` are initialized and destroyed in the default implementation. Be careful when subclassing to not introduce memory leaks.
### Security

Using a secure HTTPS connection when communicating with servers and web services is an important step in securing sensitive data. By default, Alamofire will evaluate the certificate chain provided by the server using Apple's built in validation provided by the Security framework. While this guarantees the certificate chain is valid, it does not prevent man-in-the-middle (MITM) attacks or other potential vulnerabilities. In order to mitigate MITM attacks, applications dealing with sensitive customer data or financial information should use certificate or public key pinning provided by the `ServerTrustPolicy`.
Expand Down
3 changes: 1 addition & 2 deletions Source/Manager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public class Manager {
/**
Responsible for handling all delegate callbacks for the underlying session.
*/
public final class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
public class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
private var subdelegates: [Int: Request.TaskDelegate] = [:]
private let subdelegateQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT)

Expand All @@ -229,7 +229,6 @@ public class Manager {

return subdelegate
}

set {
dispatch_barrier_async(subdelegateQueue) { self.subdelegates[task.taskIdentifier] = newValue }
}
Expand Down

0 comments on commit 971e2f8

Please sign in to comment.