Here is a list of API changes floating round my head that could be made before we declare 2.0 final:
Delegate lifecycle
Presently CK2FileManager
references its delegate weakly. The number one issue to my mind is that changing is a messy business, and something clients almost certainly shouldn't be doing. We could turn the system round so that delegate is a strong reference and specified at initialisation. The client is then responsible for shutting the manager down in order to release the delegate.
Also gives a chance for the client to specify a queue for delivering delegate messages on.
Configuration
Clients would probably like to control things like timeouts for operations. Again like the delegate, awkward questions arise if such settings can be changed mid-lifecycle. It would be neat to provide this info upfront, but doing so can easily result in a ridiculously large init…
method.
One option is to have CK2Configuration
class which encapsulates all these details.
Another idea that springs to mind is the concept of a prototypeRequest
. The client would provide a URL request configured to its liking that all operations would be derived from. There does seem a little impedance mismatch here. e.g. upload data and many HTTP headers would have to be ignored.
Task/Operation API
Presently ConnectionKit exposes the concept of an operation purely as an id
. We could make this a public class with its own API for cancelling etc. CK2Task
is nicely terse. CK2Operation
is pretty good too, but I think subtly carries the expectation it be a subclass of NSOperation
. Of course, perhaps it should be just such a subclass!
Include Task/Operation in delegate methods
Delegate methods could pass in a reference to the task/operation which they relate to, allowing the delegate to make an educated decision if multiple operations are in flight. The trick there is a subtle race condition exists whereby a delegate message could arrive before the client has had a chance to store a reference to the task/operation, leaving it unsure how to handle it.
A simple solution to that is to make the client explicitly start each operation itself. Something like:
CK2Operation *op = [fileManager createFileAtURL:…
[self addUploadOperation:op];
[op start];
If the client doesn't care about referencing the op, it can do:
[[fileManager createFileAtURL:…] start];
Would that be more confusing for clients? Perhaps the APIs ought to be renamed to reflect that they're creating a task/operation object, rather than acting immediately.
Another solution would be to ask that clients manage some form of synchronisation around calling the file manager to avoid such races. I have a nasty suspicion most wouldn't, and would only se the race condition happen sporadically once out in the wild. Hmmmm.
Oh, one other advantage of having clients explicitly start operations/tasks is that they could easily hand off to some form of queuing mechanism to manage that.
Move a little more in favour of delegate methods over blocks
For some of the more complex operations, the current block-based system might seem a little overwhelming. It might be better to shift back some control work to being done in delegate methods. This would require something as described in the previous section.
In particular uploads are an interesting problem since to handle arbitrary schemes requires handling/notification of three things:
- Upload progress
- Providence of a fresh stream
- Completion
Having three blocks passed to a method seems pretty damn unwieldy to me (I still find two to be awkward!)
Dual authentication delegate methods
CK2FileManager
could make the distinction in its delegate methods between authenticating an individual operation, and a connection. This might be too confusing for clients though, I wonder. Technically I guess FTP and SFTP work purely by authenticating a connection.
Asynchronous delegation methods
It might be nice to standardise on a model where the delegate is free to take as long as it wants responding to a message, signalling it is ready to continue by calling a block provided by the manager.
NSURLAuthenticationChallenge
already encapsulates a means of doing this in a pre-blocks world. Might be nice to generalise the principle.
Session
Originally, the main class in ConnectionKit was CK2Session
which tended to confuse people in practice into thinking it represented a single connection. With upcoming Apple APIs, that may be less confusing. If we renamed it CK2FileSession
that would produce delegate methods which carry less risk of conflicting with Apple's own ones in future. This is a pretty big change to make though!