This article is available in Serbo-Croatian,  JapaneseGerman and French.

(Translations in Serbo-Croatian by Jovana Milutinovich, Japanese by @noradaiko, German by Jonas Pencke (@jonaspencke) and French by Anna Chekovsky)

Translations in other languages are welcome!

 

How awesome would it be if a networking framework automatically takes care of caching responses for you?

How awesome would it be if a networking framework automatically remembers your operations when your client is offline?

You favorite a tweet or mark a feed as read when you are offline and the Networking Framework performs all these operations when the device comes back online, all with no extra coding effort from you. Introducing MKNetworkKit.

 

What is MKNetworkKit?

MKNetworkKit is a networking framework written in Objective-C that is seamless, block based, ARC ready and easy to use.
MKNetworkKit is inspired by the other two popular networking frameworks, ASIHTTPRequest and AFNetworking. Marrying the feature set from both, MKNetworkKit throws in a bunch of new features. In addition to this, MKNetworkKit mandates you to write slightly more code than the other frameworks at the expense of code clarity. With MKNetworkKit, it’s hard to write ugly networking code.

Features

Super light-weight

The complete kit is just 2 major classes and some category methods. This means, adopting MKNetworkKit should be super easy.

Single Shared Queue for your entire application.

Apps that depend heavily on Internet connectivity should optimize the number of concurrent network operations. Unfortunately, there is no networking framework that does this correctly. Let me give you an example of what can go wrong if you don’t optimize/control the number of concurrent network operations in your app.

Let’s assume that you are uploading a bunch of photos (think Color or Batch) to your server. Most mobile networks (3G) don’t allow more than two concurrent HTTP connections from a given IP address. That is, from your device, you cannot open more than two concurrent HTTP connections on a 3G network. Edge is even worse. You can’t, in most cases, open more than one connection. This limit is considerably high (six) on a traditional home broadband (Wifi). However, since your iDevice is not always connected to Wifi, you should be prepared for throttled/restricted network connectivity. On any normal case, the iDevice is mostly connected to a 3G network, which means, you are restricted to upload only two photos in parallel. Now, it is not the slow upload speed that hurts. The real problem arises when you open a view that loads thumbnails of photos (say on a different view) while this uploading operations are running in the background. When you don’t properly control the queue size across the app, your thumbnail loading operations will just timeout which is not really the right way to do it. The right way to do this is to prioritize your thumbnail loading operation or wait till the upload is complete and the load thumbnails. This requires you to have a single queue across the entire app. MKNetworkKit ensures this automatically by using a single shared queue for every instance of it. While MKNetworkKit is not a singleton by itself, the shared queue is.

Showing the Network Activity Indicator correctly

While there are many third party classes that uses “incrementing” and “decrementing” the number of network calls and using that to show the network activity indicator, MKNetworkKit backs on the single shared queue principle and shows the activity indicator automatically when there is an operation running in the shared queue by observing (KVO) the operationCount property. As a developer, you normally don’t have to worry about setting the network activity indicator manually, ever again.

    if (object == _sharedNetworkQueue && [keyPath isEqualToString:@"operationCount"]) {
 
        [UIApplication sharedApplication].networkActivityIndicatorVisible =
        ([_sharedNetworkQueue.operations count] > 0);
    }

Auto queue sizing

Continuing the previous discussion, I told that most mobile networks don’t allow more than two concurrent connections. So your queue size should be set to two, when the current network connectivity is 3G. MKNetworkKit automatically handles this for you. When the network drops to 3G/EDGE/GPRS, it changes the number of concurrent operations that can be performed to 2. This is automatically changed back to 6 when the device connects back to a Wifi network. With this technique in place, you will see a huge performance benefit when you are loading thumbnails (or multiple similar small requests) for a photo library from a remote server over 3G.

Auto caching

MKNetworkKit can automatically cache all your “GET” requests. When you make the same request again, MKNetworkKit calls your completion handler with the cached version of the response (if it’s available) almost immediately. It also makes a call to the remote server again. After the server data is fetched, your completion handler is called again with the new response data. This means, you don’t have to handle caching manually on your side. All you need to do is call one method,

[[MKNetworkEngine sharedEngine] useCache];

Optionally, you can override methods in your MKNetworkEngine subclass to customize your cache directory and in-memory cache cost.

Operation freezing

With MKNetworkKit, you have the ability to freeze your network operations. When you freeze an operation, in case of network connectivity losses, they will be serialized automatically and performed once the device comes back online. Think of “drafts” in your twitter client.

When you post a tweet, mark that network call as freezable and MKNetworkKit automatically takes care of freezing and restoring these requests for you! So the tweets get sent later without you writing a single line of additional code. You can use this for other operations like favoring a tweet or sharing a post from your Google reader client, adding a link to Instapaper and similar operations.

Performs exactly one operation for similar requests

When you load thumbnails (for a twitter stream), you might end up creating a new request for every avatar image. But in reality, you only need as many requests as there are unique URLs. With MKNetworkKit, every GET request you queue gets executed exactly once. MKNetworkKit is intelligent enough not to cache “POST” http requests.

Image Caching

MKNetworkKit can be seamlessly used for caching thumbnail images. By overriding a few methods, you can set how many images should be held in the in-memory cache and where in the Caches directory it should be saved. Overriding these methods are completely optional.

Performance

One word. SPEED. MKNetworkKit caching is seamless. It works like NSCache, except that, when there is a memory warning, the in-memory cache is written to the Caches directory.

Full support for Objective-C ARC

You normally choose a new networking framework for new projects. MKNetworkKit is not meant for replacing your existing framework (though you can, it’s quite a tedious job). On new projects, you will almost and always want to enable ARC and as on date of writing this, MKNetworkKit is probably the only networking framework that is fully ARC ready. ARC based memory management is usually an order of magnitude faster than non-ARC based memory management code.

How to use

Ok, Enough self-praises. Let us now see how to use the framework.

Adding the MKNetworkKit

  1. Drag the MKNetworkKit directory to your project.
  2. Add the CFNetwork.Framework, SystemConfiguration.framework, Security.framework and ImageIO.Framework.
  3. Include MKNetworkKit.h to your PCH file
  4. Delete NSAlert+MKNetworkKitAdditions.h file if you are building for iOS.
  5. Delete UIAlertView+MKNetworkKitAdditions.h file if you are building for Mac.

You are done. Just 5 core files and there you go. A powerful networking kit.

Classes in MKNetworkKit

  1. MKNetworkOperation
  2. MKNetworkEngine
  3. Miscellaneous helper classes (Apple’s Reachability) and categories

I believe in simplicity. Apple has done the heavy lifting of writing the actual networking code. What a third-party networking framework should provide is an elegant queue based networking with optional caching. I believe that, any third party framework should have under 10 classes (whether it’s networking or UIKit replacement or whatever). More than that is a bloat. Three 20 library is an example of bloat and so is ShareKit. May be it’s good. But it still huge and bloated. ASIHttpRequest or AFNetworking are lean and lightweight, unlike RESTKit. JSONKit is lightweight unlike TouchJSON (or any of the TouchCode libraries). May be it’s just me, but I just can’t take it when more than a third of source code lines in my app comes from a third party library.

The problem with a huge framework is the difficulty in understanding the internal working and the ability to customize it to suit your needs (in case you need to). My frameworks (MKStoreKit for adding In App Purchases to your app) have always been super easy to use and I believe MKNetworkKit would also be the same. For using MKNetworkKit, all you need to know are the methods exposed by the two classes MKNetworkOperation and MKNetworkEngine. MKNetworkOperation is similar to the ASIHttpRequest class. It is a subclass of NSOperation and it wraps your request and response classes. You create a MKNetworkOperation for every network operation you need in your application.

MKNetworkEngine is a pseudo-singleton class that manages the network queue in your application. It’s a pseudo-singleton, in the sense, for simple requests, you should use MKNetworkEngine methods directly. For more powerful customization, you should subclass it. Every MKNetworkEngine subclass has its own Reachability object that notifies it of server reachability notifications. You should consider creating a subclass of MKNetworkEngine for every unique REST server you use. It’s pseudo-singleton in the sense, every single request in any of it’s subclass goes through one and only one single queue.

You can retain instances of your MKNetworkEngine in your application delegate just like CoreData managedObjectContext class. When you use MKNetworkKit, you create an MKNetworkEngine sub class to logically group your network calls. That is, all Yahoo related methods go under one single class and all Facebook related methods into another class. We will now look at three different examples of using this framework.

Example 1:

Let’s now create a “YahooEngine” that pulls currency exchange rates from Yahoo finance.

Step 1: Create a YahooEngine class as a subclass of MKNetworkEngine. MKNetworkEngine init method takes hostname and custom headers (if any). The custom headers is optional and can be nil. If you are writing your own REST server (unlike this case), you might consider adding client app version and other misc data like client identifier.

    NSMutableDictionary *headerFields = [NSMutableDictionary dictionary];
    [headerFields setValue:@"iOS" forKey:@"x-client-identifier"];
 
    self.engine = [[YahooEngine alloc] initWithHostName:@"download.finance.yahoo.com"
                       customHeaderFields:headerFields];

Note that, while yahoo doesn’t mandate you to send x-client-identifier in the header, the sample code shown above sends this just to illustrate this feature.

Since the complete code is ARC, it’s up to you as a developer to own (strong reference) the Engine instance.

When you create a MKNetworkEngine subclass, Reachability implementation is done automatically for you. That’s when your server goes down or due to some unforeseen circumstances, the hostname is not reachable, your requests will automatically be queued/frozen. For more information about freezing your operations, read the section Freezing Operations later in the page.

Step 2: Designing the Engine class (Separation of concerns)

Let’s now start write the methods in Yahoo Engine to fetch exchange rates. The engine methods will be called from your view controller. A good design practice is to ensure that your engine class doesn’t expose URL/HTTPHeaders to the calling class. Your view should not “know” about URL endpoints or the parameters needed. This means, parameters to methods in your Yahoo Engine should be the currencies and the number of currency units. The return value of this method could be a double value that is the exchange rate factor and may be the timestamp of the time it was fetched. Since operations are not performed synchronously, you should return these values on blocks. An example of this would be,

-(MKNetworkOperation*) currencyRateFor:(NSString*) sourceCurrency
                   	    inCurrency:(NSString*) targetCurrency
			  onCompletion:(CurrencyResponseBlock) completion
        	               onError:(ErrorBlock) error;

MKNetworkEngine, the parent class defines three types of block methods as below.

typedef void (^ProgressBlock)(double progress);
typedef void (^ResponseBlock)(MKNetworkOperation* operation);
typedef void (^ErrorBlock)(NSError* error);

In our YahooEngine, we are using a new kind of block, CurrencyResponseBlock that returns the exchange rate. The definition looks like this.

typedef void (^CurrencyResponseBlock)(double rate);

In any normal application, you should be defining your own block methods similar to this CurrencyResponseBlock for sending data back to the view controllers.

Step 3: Processing the data
Data processing, that is converting the data you fetch from your server, whether it’s JSON or XML or binary plists, should be done in your Engine. Again, relieve your controllers of doing this task. Your engine should send back data only in proper model objects or arrays of model objects (in case of lists). Convert your JSON/XML to models in the engine. Again, to ensure proper separation of concerns, your view controller should not “know” about the “keys” for accessing individual elements in your JSON.

That concludes the design of your Engine. Most networking framework doesn’t force you to follow this separation of concerns. We do, because we care for you :)

Step 4: Method implementation
We will now discuss the implementation details of the method that calculates your currency exchange.

Getting currency information from Yahoo, is as simple as making a GET request.
I wrote a macro to format this URL for a given currency pair.

#define YAHOO_URL(__C1__, __C2__) [NSString stringWithFormat:@"d/quotes.csv?e=.csv&f=sl1d1t1&s=%@%@=X", __C1__, __C2__]

Methods you write in your engine class should do the following in order.

  1. Prepare your URL from the parameters.
  2. Create a MKNetworkOperation object for the request.
  3. Set your method parameters.
  4. Add completion and error handlers to the operation (The completion handler is the place to process your responses and convert them to Models.)
  5. Optionally, add progress handlers to the operation. (Or do this on the view controller)
  6. If your operation is file download, set a download stream (normally a file) to it. This is again optional.
  7. When the operation completes, process the result and invoke the block method to return this data to the calling method.

This is illustrated in the following code

        MKNetworkOperation *op = [self operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency)
                                                  params:nil
                                             httpMethod:@"GET"];
 
    [op onCompletion:^(MKNetworkOperation *completedOperation)
     {
         DLog(@"%@", [completedOperation responseString]);
 
		 // do your processing here
         completionBlock(5.0f);
 
     }onError:^(NSError* error) {
 
         errorBlock(error);
     }];
 
    [self enqueueOperation:op];
 
    return op;

The above code formats the URL and creates a MKNetworkOperation. After setting the completion and error handlers it queues the operation by calling the super class’s enqueueOperation method and returns a reference to it. Your view controller should own this operation and cancel it when the view is popped out of the view controller hierarchy. So if you call the engine method in, say viewDidAppear, cancel the operation in viewWillDisappear. Canceling the operation will free up the queue for performing other operations in the subsequent view (Remember, only two operations can be performed in parallel on a mobile network. Canceling your operations when they are no longer needed goes a long way in ensuring performance and speed of your app).

You view controller can also (optionally) add progress handlers and update the user interface. This is illustrated below.

    [self.uploadOperation onUploadProgressChanged:^(double progress) {
 
        DLog(@"%.2f", progress*100.0);
        self.uploadProgessBar.progress = progress;
    }];

MKNetworkEngine also has convenience methods to create a operation with just a URL. So the first line of code can also be written as

        MKNetworkOperation *op = [self operationWithPath:YAHOO_URL(sourceCurrency, targetCurrency)];

Do note here that request URLs are automatically prefixed with the hostname you provided while initializing your engine class.

Creating a POST, DELETE or PUT method is as easy as changing the httpMethod parameter. MKNetworkEngine has more convenience methods like this. Read the header file for more.

Example 2:

Uploading an image to a server (TwitPic for instance).
Now let us go through an example of how to upload an image to a server. Uploading an image obviously requires the operation to be encoded as a multi-part form data. MKNetworkKit follows a pattern similar to ASIHttpRequest.
You call a method addFile:forKey: in MKNetworkOperation to “attach” a file as a multi-part form data to your request. It’s that easy.
MKNetworkOperation also has a convenience method to add a image from a NSData pointer. That’s you can call addData:forKey: method to upload a image to your server directly from NSData pointer. (Think of uploading a picture from camera directly).

Example 3:

Downloading files to a local directory (Caching)
Downloading a file from a remote server and saving it to a location on users’ iPhone is super easy with MKNetworkKit.
Just set the outputStream of MKNetworkOperation and you are set.

[operation setDownloadStream:[NSOutputStream
	outputStreamToFileAtPath:@"/Users/mugunth/Desktop/DownloadedFile.pdf"
			  append:YES]];

You can set multiple output streams to a single operation to save the same file to multiple locations (Say one to your cache directory and one to your working directory)

Example 4:

Image Thumbnail caching
For downloading images, you might probably need to provide an absolute URL rather than a path. MKNetworkEngine has a convenience method for this. Just call operationWithURLString:params:httpMethod: to create a network operation with an absolute URL.
MKNetworkEngine is intelligent. It coalesces multiple GET calls to the same URL into one and notifies all the blocks when that one operation completes. This drastically improves the speed of fetching your image URLs for populating thumbnails.

Subclass MKNetworkEngine and override image cache directory and cache cost. If you don’t want to customize these two, you can directly call MKNetworkEngine methods to download images for you. I would actually recommend you to do that.

Caching operations

MKNetworkKit caches all requests by default. All you need to do is to turn on caching for your Engine. When a GET request is performed, if the response was previously cached, your completion handler is called with the cached response almost immediately. To know whether the response is cached, use the isCachedResponse method. This is illustrated below.

    [op onCompletion:^(MKNetworkOperation *completedOperation)
     {
         if([completedOperation isCachedResponse]) {
             DLog(@"Data from cache");
         }
         else {
             DLog(@"Data from server");
         }
 
         DLog(@"%@", [completedOperation responseString]);
     }onError:^(NSError* error) {
 
         errorBlock(error);
     }];

Freezing operations

Arguably, the most interesting feature of MKNetworkKit is built in ability to freeze operations. All you need to do is set your operation as freezable. Almost zero effort!

[op setFreezable:YES];

Freezable operations are automatically serialized when the network goes down and executed when connectivity is restored. Think of having the ability to favorite a tweet while you are offline and the operation is performed when you are online later.
Frozen operations are also persisted to disk when the app enters background. They will be automatically performed when the app is resumes later.

Convenience methods in MKNetworkOperation

MKNetworkOperation exposes convenience methods like the following to get the format your response data.

  1. responseData
  2. responseString
  3. responseJSON (Only on iOS 5)
  4. responseImage
  5. responseXML
  6. error

They come handy when accessing the response after your network operation completes. When the format is wrong, these methods return nil. For example, trying to access responseImage when the actual response is a HTML response will return nil. The only method that is guaranteed to return the correct, expected response is responseData. Use the other methods if you are sure of the response type.

Convenience macros

The macros, DLog and ALog were stolen unabashedly from Stackoverflow and I couldn’t again find the source. If you wrote that, let me know.

A note on GCD

I purposefully didn’t use GCD because, network operations need to be stopped and prioritized at will. GCD, while more efficient than NSOperationQueue, cannot do this. I would recommend not to use GCD based queues for your network operations.

Documentation

The header files are commented and I’m trying out headerdoc from Apple. Meanwhile, you can use/play around (read: Fork) with the code.

Source Code

The source code for MKNetworkKit along with a demo application is available on Github.
MKNetworkKit on Github

Feature requests

Please don’t email me feature requests. The best way is to create an issue on Github.

Licensing

MKNetworkKit is licensed under MIT License

All of my source code can be used free of charge in your app, provided you add the copyright notices to your app. A little mention on one of your most obscure “about” page will do.

Attribution free licensing available upon request. Contact me at mknetworkkit@mk.sg


Mugunth


Follow me on Twitter

  • puran

    Even though this looks very impressive. The number of issues in github makes me think twice before i use this. But i feel like i should go for it!!

  • Devang

    Does operation freezing also archive the completion and error blocks? I tried it with some logs in the completion and error blocks but it didn’t look like it worked.

    • MugunthKumar

      No. Blocks capture the complete stack. As such it’s impossible to serialize.

      • Devang

        Would you have any suggestion on what can be done if any statements need to be called after a query is completed. If not blocks, then even selectors can be used which probably don’t necessitate capturing the complete stack.

        • MugunthKumar

          NSNotifications

          • Devang

            I think I am missing a reference here. I can probably save the information I need to pass in a the notifications userInfo dictionary. But who will post the notification here and how can I trigger the notification once the MKNetworkOperation succeeds/fails? I thought you said those parts of the operations essentially become non-functional when the MKNetworkOperation is run after being unarchived.

          • Devang

             Is there any NSNotifications being sent in MKNetworkOperation when an operation completes?

          • MugunthKumar

            Right now, No. I’m working on it.

            Sent from my iPad
            Mugunth
            Author | Developer | Trainer
            Get my iOS 5 Programming book
            iBooks: http://mk.sg/ibook
            Amazon: http://mk.sg/ios5book

  • paul

    is this library still alive or it’s defunct because as i see in github there are a lot of issues and there are no answers and no updates, i guess we will switch to a more robust and bug free library

  • Summer

    Please add support for Passing an NSArray to the  MKNetworkOperation for a POST

  • Paul

    Mugunth, as others have said, great book, and MKNetworkKit isn’t bad either :-)
    I need to do a post to server of a single block of XML, pre-formatted in a message.  No params other than the XML in the message body.  Is there anyway to set the message Body explicitly and leave the params component nil ?
    Thanks

    Paul

    • MugunthKumar

      If you are trying to set XML for a SOAP service, try MKNKPostDataEncodingTypePlist To completely customize the post body, you can use setCustomPostDataEncodingHandler
      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

      • Paul

        Mugunth, outstanding quick reply !   Can I ask if you have an example of this one ?  Have had a quick look in the kit but can’t see an easy to understand example or reference to MKNKPostDataEncodingTypePlist.

        Thanks,
        Paul

      • Paul

        Mugunth,  have had a chance to look at this a little.If I setPostDataEncoding to MKNKPostDataEncodingTypePlist how do I tell the op what the XML is ?  Does that go as a param and if so what is the dictionary key to use ?  (I guess if a param dictionary is used, the actual XML as a String goes as the object, but what key to use ?)
        Thanks for your help on this.

        Paul

        • MugunthKumar

          The params dictionary is encoded as XML. The XML encoding would look like Xcode’s Info.plist When you use XML encoding, there is no “key” or “value”. key/value pairs are used only for application/x-www-form-urlencoded
          Mugunth
          Author | Developer | Trainer
          iOS 5 Programming book
          iBooks: http://mk.sg/ibook
          Amazon: http://mk.sg/ios5book

          • Paul

            Mugunth, not sure I understand here.  The param arguments to your calls take a NSDictionary ?  An NSDictionary by default stores name/value pairs. Dont understand how you can construct one to take a single argument with XML ?  Unless you mean pass an NSString with xml as the param ? (which seems wrong for type casting) to your call in place of the Dict ?
            So in order to set the body of the message to XML, I can set the postDataEncoding so the Operation and Engine know what they are dealing with. But how do I pass a block of XML to the Operation to be placed in the body ?You are correct, this is a _sort_ of SOAP messaging.ThanksPaul

          • MugunthKumar

            Try creating a xplist file in Xcode, you will understand.
            It’s encoding type is similar to your app’s Info.plist.
            One dictionary gets converted to a XML file (NSString).

            For SOAP, you have to use customPostDataHandler block. No otherway. MKNetworkKit (and I guess nearly every networking framework) will not support SOAP by default.
            Mugunth
            Author | Developer | Trainer
            iOS 5 Programming book
            iBooks: http://mk.sg/ibook
            Amazon: http://mk.sg/ios5book

  • Paul

    Mugunth, looking at the GitHub front page, you mentioned you were going to document how to compile into a static library ?  Did that doc get finished yet ?
    If not, can you give any pointers on how to do this.  I have file downloads etc working fine now in a standalone app, but I want to put the routines into a static lib to be able to use across our other apps.

    Thanks

    Paul

    • Paul

      Mugunth, problem sorted.  I have it working now correctly in a library.  Problem earlier was the use of a sleep in a library method, blocking the execution of the rest of the library functions

  • Sambasiva Rao D

    Hi Mugunth,

    Thank you for very nice library. I have a small problem in uploading an image. If I have image key inside dictionary, how I can pass the key.

    “UploadPropertyPicture”:{
    “FileType”:”jpg”,
    “UploadedFile”:”image data”
    }

    Please help me.

    Thanks
    Shiva

  • Jeebee

    Hi, this kit is excellent.But I find that the memory can not be released when I using the kit.Would you help to fix this problem?Thanks in advanced.

    • MugunthKumar

      Memory won’t be released till system sends a memory warning. All cache is stored in memory

  • Claus

    If we are trying to keep knowledge of URLs, etc., out of our view controller, why does your example pass the Yahoo URL to the engine subclass from the view controller (or whatever happens to instantiate the engine)? Wouldn’t it make more sense for YahooEngine to maintain this URL internally?

  • http://www.facebook.com/magnusottosson Magnus Ottosson

    Hi,

    I have a question about how the cache works. If I place a request and the response is cached I get a callback with the cached the result. But MKNetworkKit also performs a request to the server and I get another callback with a result that is not cached?

    Why do you make this second request if you have a cached result?

    • Pym

      I got the second response callback too 

      • MugunthKumar

        Content on the server could have changed. The cache acts as a “placeholder” till the data is fetched. Again, MKNetworkKit doesn’t make a server request if the cache headers dictate not to.
        Mugunth
        Author | Developer | Trainer
        iostraining.sg
        Preorder the iOS 6 Programming Pushing the Limits book http://mk.sg/ios6book

  • Michiel Van Baak

    Can I download more then one file in one Operation?
    The .h files tells me I can run addDownloadStream multiple times, but it will not do what I want.
    I have a bunch of files on my server that I want to download, and I want to show a progressbar for it…

    My code so far (which is not working, it only downloads the first video correctly)

    NSEnumerator *enumerator = [appVideos objectEnumerator];
    id anObject;
    while (anObject = [enumerator nextObject]) {
      NSLog(@”Going to download the movie file %@ %@”, [anObject valueForKey:@"downloadUrl"], [anObject valueForKey:@"name"]);
      NSLog(@”Adding download stream”);
      NSString *videoFilePath = [videoFolder stringByAppendingPathComponent:[anObject valueForKey:@"name"]];
      [op addDownloadStream:[NSOutputStream outputStreamToFileAtPath:videoFilePath append:YES]];}…[self.updateOperation onDownloadProgressChanged:^(double progress) {
       pb.progress = progress;
    }];

    Can someone give me a hint ?

    • MugunthKumar

      One operation points to one URL. One URL can point to only one file. You should use multiple operations to download multiple files.

      The addDownloadOperation is to add multiple destinations to the same file.

      • Michiel Van Baak

        Yeah, I found out tonight.
        Is there an ‘easy’ way to have something like onCompletion for the operation, for the whole queue? I want to show the user a progressbar while downloading 12 files, and only dismiss it when all 12 files are done (12 operations) … 
        Small detail: the files come from an array I get from a webservice, so the number is not always 12 ….

        Thank you for this framework, it already helped me a lot.

  • alex904

    Seriously, $130/h consulting fee for an idiot who can’t build proper XCode project and include NSData+Base64 into exporting symbols? Huh?

  • cy

    hi,
    you mention about it is a network queue, so to use it to download files mean I create an operation, then keep calling the same method from the same engine? each call will then automatic queue itself and do the job? am I right?

    thank you.

  • Prosko

    I get 32 compilation errors when I run the demo prorgram:

    Array subscript is not an integer – This error occurs 13 times in MKNetworkEngine.m

    MKNetworkOperation.m

    Unknown receiver ‘_connection’; did you mean ‘NSConnection’?

    Receiver ‘NSConnection’ for class message is a forward declaration

    No known class method for selector ‘cancel’

    Unknown type name ‘_connection’; did you mean ‘NSConnection’?

    Expected identifier or ‘(‘

    • MugunthKumar

      The latest code doesn’t work on Xcode 4.4 and below.
      Update your Xcode

  • nikhil

    how can we add streaming request feature to MKNetwork kit which is already provided in AFNetworkkit ?

  • http://sikosis.com/ Sikosis

    Your demo iOS code won’t run. Says it’s missing “libMKNetworkKit-iOS.a”

    • MugunthKumar

      You should open the workspace file and not the project file.

  • Max

    I want to do some form posts to my webservice but I would like to GZip the content being sent – can you do that with MKNetworkKit?

    • MugunthKumar

      Yes, just set the content encoding type to gzip

      • Max

        So something like this?

        NSMutableDictionary *paymentEngineHeaders = [NSMutableDictionary dictionary];
        [paymentEngineHeaders setValue:@"gzip" forKey:@"content-encoding"];
        self.paymentEngine = [[PaymentEngine alloc] initWithHostName:kHostName customHeaderFields:paymentEngineHeaders];

        • MugunthKumar

          Exactly.

          • Max

            Doing that get’s me a little further but I then end up with this error:

            The magic number in GZip header is not correct. Make sure you are passing in a GZip stream.

            This web service call is working using ASIHTTPRequest but I am trying to migrate over to MKNetworkKit.

            Could there be something simple I am missing here?

          • MugunthKumar

            Can you try setting gzip to Accept-Encoding as well?

            Mugunth
            Author | Developer | Trainer
            iostraining.sg
            Preorder the iOS 6 Programming Pushing the Limits book http://mk.sg/ios6book

  • http://twitter.com/kbbajwa Khalid Bashir Bajwa

    Hi Mugunth Kumar great work. I want to continue uploading even if iOS app enters background. Something similar could be done with ASIHTTPRequest. Is it possible with MKNetworkKit. Really looking forward.

    Thanks a lot.

  • http://twitter.com/bmauter Brian Mauter

    Hi, thanks for the kit. I’m trying it out for my next app. The web services that I’m supposed to call aren’t in place yet. How would you suggest mocking it out?

    Ideally, I’d like to create a protocol with all of my business methods in it. My class extending MKNetworkEngine would implement that protocol and so would my mock object.

    I don’t like having to return MKNetworkOperation because it makes the mock messy. How would you go about this?

    Thanks!

  • http://twitter.com/Nolan_Ratu Nolan Ratu

    Hi,
    What an awesome framework and it works a treat. I am using it to download a pdf file and saving it to my cache and demo app. I want the user to select and download different pdf files. But just over writes the previous pdf file. Is there a way to allow for many pdf files to be download and saved to the cache directory? Thanks

    • MugunthKumar

      For downloading files, try the stream handlers. You should be able to save them to any NSOutputStream. Check the PDF download example in the demo.
      Sent from my iPad
      Mugunth
      Author | Developer | Trainer
      iostraining.sg
      Preorder the iOS 6 Programming Pushing the Limits book http://mk.sg/ios6book

      • http://twitter.com/Nolan_Ratu Nolan Ratu

        Sorry, what I meant was saving a pdf file with a different name every time they download it.

  • Jesse Hemingway

    Not bad. Requiring subclassing is a weakness, but perhaps that’s not necessary, will dig in further, time permitting. If time does not permit, I’ll have to go AF as it does not require subclassing to use its network queue. Your library has a lot of feature similarities to one I built including ‘freezing’ of requests that can’t be handled right away. Nice work!

  • deepak k

    is there any inbuilt activity indicator support in MK?

    • MugunthKumar

      Yes

  • Nigel Collins

    Hi – Can I use this framework to download a number of large (50MBit) files and save to app library?

  • http://twitter.com/mymacapps Gonzalo

    Thank Mugunth for awesome library.

    I have a problem. When I download a file I can not make requests for my server. The answer of the server arrive when the download is complete.

    For download from my server I use your library, for other request of my server I use simple NSURLConnection.

    Any idea?

    Best,

  • http://twitter.com/ryoushi77 ryoushi77

    Hello,
    does MKNetworkKit supports the functionality of stopping and resuming downloads? When so, could you maybe hint me in the right direction?

    • http://mugunthkumar.com Mugunth Kumar

      Yes, provided your server supports range headers

  • Zed Scio

    When an image exists in the cache, is the cached image returned and the flow stops there or is the image also refetched and the response block is hit again with the new image? Particulary with the imageAtURL method

  • Massimo Donati

    Hi,

    I will totally try this!! Just a problem on running the iOS demo on ios6

    Apple Mach-O Linker Error! How should i fix this?

    • MugunthKumar

      You should open the workspace and not the project

      • Massimo Donati

        ok thanks for your time!

  • http://www.facebook.com/mark.putnam.5817 Mark Putnam

    Well done! I like very much the design of MKNetworkKit. One quick question. Is there a way to get the URL of the local cached file? I am caching .m4v files fine, but then need a “local” url in order to init a MPMoviePlayerController. Ideas?

  • http://twitter.com/ebernet ebernet

    Thanks for a great project. I am using it on iOS. I am using it to do a POST, and am getting back a fully formed web page (I am trying to do some web page scraping). I am trying to see the data as a string, or HTML, but what I get is Hex data. What is the trick that will let me view it as string data? Is there a trick I can use to skip data until I get to a specific part in the HTML? Sadly, the website I am trying to use has no real response object, so I must parse the HTML – is there a different framework you would recommend? Thank you so much for your help.

    • http://twitter.com/ebernet ebernet

      Nevermind. I think I found the way to do it. Put it in an NSXML parser, look for the elements I want, and go from there. Thank you!

  • Massimo Donati

    Hi i’m trying to figure out how to log in on a home made server (as in the image). How should i do it?

  • Daniel

    Hi. Is there any way to know when all the enqueue MKNetworkOperation finish? It would be very nice.

  • http://darkredz.com/ Leng Sheng Hong

    addDownloadStream to download it directly to a file. By default if server supports resume, MKNetworkKit honors it. Question is when will it resume? What method should be called to resume the download? Say I close the app and restarted, what should be called to resume download for the file?

  • 182459312

    Hi, MugunthKumar .
    Why are you for the SDK development package called “MKNetworkKit”? Are you like MK (King of the hill in War3)? Your SDK development package really strong, but the project configuration do a bit lacking oh! best wish to you!!

  • http://www.facebook.com/mark.putnam.5817 Mark Putnam

    Ciao MK, A couple of months ago I posted…

    Well done! I like very much the design of MKNetworkKit. One quick
    question. Is there a way to get the URL of the local cached file? I am
    caching .m4v files fine, but then need a “local” url in order to init a
    MPMoviePlayerController. Ideas?

    … but got no response. Now I’m committed to MKNetworkKit, but have run up against this issue again.

    Here’s my problem. My app must run off-line, so I cache a pile of assets for use when off-line. PDFs, Images, etc. are fine because I am handling the asset directly. Unfortunately, MPMoviePlayerController expects a URL to the destination file so it can handle ‘local steaming.’ I need to know what the local URL is to my cached movie file. When using ASIHTTPDownloadCache I was able to call pathToCachedResponseDataForURL:

    Does MKNetworkKit offer anything similar? I looked for something in the MKNetworkOperation class, but couldn’t it out.

    You kind help is very much appreciated.

  • Jeffrey Berthiaume

    I added the latest MKNetworkKit to a new project, and it required me to add the ImageIO framework. You might want to update the framework requirements above. Thanks!

    • MugunthKumar

      Thanks, updated!

      Mugunth
      Author | Developer | Trainer
      iostraining.sg
      iOS 6 Programming Pushing the Limits book
      http://mk.sg/ios6book

  • Tommy

    I just want to send a string to server,what should we do?

  • Tommy

    hello, i just want send a string, not json object,what shoud we do.

  • Marcel Timmermans

    Is it possible to do a post with same keys like:

    Username=test&b=1&b=2&b=3

  • Zahur

    Hi,
    I am developing using workspace, is there a way something like edit the pod file and install this library? If yes please suggest step by step

  • JasonJ.

    Is it possible to flush memory cache to dick manually?

  • Sven

    In Example 1 there are three typedefs whhick MKNetworkEngine should define, but it doesn’t

  • Taylor Marks

    Since onCompletion:onError: is deprecated, shouldn’t you update this blog post to show addCompetitionHandler:errorHandler: instead?