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

  • Enrique Santos

    Wow, just wow. We were developing our own version of a network framework, but I think yours fits almost perfectly. A million thanks.

    Just one question, does MKNetworkKit use _weak properties or variables? We are looking to use it in an app targeting iOS4, and if I got it correctly you cannot use _weak properties or variables when targeting versions lesser than iOS5.

    Thanks in advance,
    Enrique Santos

    • Anonymous

      I don’t remember using weak, if it’s, it’s a bug. I’ll update github shortly with the fix

      • Enrique Santos

        Hi,

        Sorry, we were not saying that it was using weak, we didn’t try it yet, and we were just asking before starting to work with it. We will give it a try then :-).

        Thanks again for the great work.
        Enrique

  • Jin

    Thank you for your source :)
    I have a problem. I unzip it and run iOS demo. But I can not libMKNetworkKit-iOS.a

    • Anonymous

      Can you close the latest from github instead?

      • Jin

        Oops!
        Sorry, It’s my mistake T..T

        Thanks :)

        • jay

          how did you resolve it i have same problem

          • Anonymous

            Open the workspace file instead of the project file

  • Mark Norgren

    I believe I am getting the same error as Jin when I attempt to run the Demo app.

    I may be doing something incorrectly, but I am not able to add the library correctly.XCode Error:

    ld: library not found for -lMKNetworkKit-iOS
    Command /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/clang failed with exit code 1

    • Anonymous

      Ok, My bad.
      The Xcode 4 workspace was missing in the repo due to a wrong .gitignore file which is why the Demo app wasn’t able to locate the workspace and inturn the static library.
      Can you try again now? I created a new tag v0.82 that fixes this.

      Even otherwise, you can just drag the MKNetworkKit related files into your own project and try it out.
      Mugunth
      Pre-order my iOS 5 Programming book
      http://mk.sg/ios5book

      • Mark

        It appears to still have the same issue. I have tried a few different things to try and fix it, still going to try a few more.

        Shouldn’t you be including the library file for the statically linked demo project?

        • Anonymous

          Did you open the workspace file or you opened the project directly? You should open the workspace. The iOS project standalone doesn’t know about the static library

          • Mark

            Yes, that is what I was doing! Sorry about that, that was my bad!
            Thanks for the help! I am excited to learn more about this mknetworkkit!
            Thanks!

  • Mark

    You mention that ShareKit is bloated, do you have a recommendation for an alternative?

    Also I notice that your book is listed on Amazon to be released December 20th. Is there anyway to get a electronic review copy before my hard-copy ships?

    Thanks!

  • You say it would be possible but tedious to replace an existing framework? This looks good and I’m considering if it might be a worthwhile replacement for ASIHTTPRequest.

    • Anonymous

      It is a worth while replacement esp, if you are migrating your project completely to ARC. Just that it takes about half a day or so

  • Anonymous

    Hi,

    Thanks for this great lib, but there is a problem with the installation of the last version.

    You need to include the “Security.framework” used by MKOperation to make it build !

    • Anonymous

      Yes, security and authentication was added last week after the blog was written. Will update the blog post accordingly.

      Thanks!

  • I am testing it right now and it seems great and really simple to use. But I have a question. In ASIHTTPRequest you can set the cache in such a way that it will only download data if it has changed from the last download. That’s not possible right now with  MKNetworkKit, correct? I can only find a way to set a time limit.

    • Anonymous

      MKNetworkKit automatically does that based on Cache-Control headers sent by the server.

      So again, no explicit tweaks necessary from implementers!

  • Anonymous

    In ASIHTTP, the queue can notify when it’s complete. I don’t see a way to do that in MKNK. The reason I’d like to have this is I’m downloading a bunch of update data and I want to write it to my db when they’re all done.

  • shae

    Hi,
    Followed your instructions to install.
    the damn thing won’t compile, seems like it won’t follow the if rule : #if TARGET_OS_MAC

    it gives me this :

    NSAlert+MKNetworkKitAdditions.h:27:9: fatal error: ‘AppKit/AppKit.h’ file not found

    any idea? 
    thx

    • Anonymous

      The file belongs to Mac. You can delete it if you are building for iOS. I’ve updated the blog as well.

      Thanks.

      Mugunth
      Pre-order my iOS 5 Programming book
      http://mk.sg/ios5book

      • shae

        Thank you for the quick answer !
        Problem solved, works like a charm :)

  • Hey, thanks a lot for the awesome kit. I’m actually trying to use it and I’m having this weird error. I guess its related to the caching mechanism.

    After some network requests, my application crashes and the debugger points to this:

    Any idea what I might be missing?!

    • Anonymous

      Can you send me a stack trace?
      Add a “Exception breakpoint” in your Xcode breakpoints navigator and send me a screenshot.
      Thanks
      Mugunth

      • Sure, here you go. Sorry I’m late but it didnt notify me that you replied!

        Let me know if this is not what you want!

  • Maxim

    hey, if i’m developing an app for ios4.0+ can i still use your framework?

  • Anonymous

    Yes, iOS 4+ is supported. Just ensure that you use -fobjc-arc for MKNetworkKit files
    Mugunth
    Author | Developer | Trainer
    iOS 5 Programming book
    iBooks: http://mk.sg/ibook
    Amazon: http://mk.sg/ios5book

  • Chris

    Any plans for gzip support?

  • Russell

    I just downloaded and ran through these examples to consider use for an upcoming iOS project.  Still learning but looks very nice.  Thanks for making this available.
    Question: Under section Adding the MKNetworkKit item #4 describes deleting a header (.h) file.    4. Delete NSAlert+MKNetworkKitAdditions.h file if you are building for iOS.Am I correct in assuming that the associated modules (.m) should also be deleted?

    Observation:  The two code samples in Example 1 Step 2 use type ErrorBlock rather than MKNKErrorBlock.  This was the first thing I pasted after adding the MKNetworkKit folder to my project, so threw me for a bit.

  • Brian Christo

    Hi

    Its an awesome network kit… Good performance, ARC support and I just love it…

    I m facing one prob in my app.. I am doing multiple file downloads using for loop….

    And I have a cancel option. When i click the cancel button, all the download operations has to be stopped or cancelled. But in my case, the operations are not cancelled. The download continues and the connection:didReceiveData of MKNetworkOperation.m is called until all those download completes…

    I have attached the screenshots of my code..I am always getting the log as “self.downloadOperation is not Cancelled”.. and the download continues till the end… I want to cancel all existing download operations totally…. What can I do?

    Please have a look and help me with some ideas…

    Brian.

    • Russell

      It looks like you are looping through mediaFilesAry and starting an operation for each mediaFile. You are overwriting self.downloadOperation each loop iteration, so cancelOperation is only canceling the operation for the last mediaFile in mediaFilesAry. If you come up with an elegant design pattern to cancel everything at once, please post it as I would like to use it.

  • Anonymous

    You are right

  • Abhishek Chatterjee

    The application crashes when i am trying the iPhone-example.SIGABRT

    • Anonymous

      Which example?

  • Shne

    Have anyone created a sample project demonstrating the functionality ?Beginners like me would benefit :S

    • Anonymous

      The source code in github contains a sample project. Did that help?

  • Thomas Elstner

    MKNetworkKit is awesome – while looking for a replacement for the abandoned ASIHTTPRequest I first had a look at AFNetworking and then I found MKNetworkKit. Very lightweight, very easy to use. I’m still fascinated by the design, e.g. setCustomPostDataEncodingHandler:forType:
    Well, it still has some issues, but it’s up to us to support MK and to report or even fix those problems.

    Cheers,
    Thomas

  • Shne

    How can i save the JSON response to an NSDictionary, I did the following but it doesn’t work that way

    NSDictionary *valueDic = [[completedOperation responseJSON] objectForKey:@”value”];

    • Anonymous

      responseJSON works only on iOS 5

      • Shne

        Is there a workaround for iOS4? because i have to support both iOS4 and 5 in my application

        • Anonymous

          Subclass MKNO and override that method and call
          [super responseJSON] for iOS5 and return JSONKit(or equivalent) based dictionary for other versions

          • Shne

            Sorry i am still learning, this is what i got so far >

            In the MKNetworkOperation.h 
            ======================
            @protocol MKNetworkOperationAPIDelegate

            @required

            – (id)initWithURLString:(NSString *)aURLString

                             params:(NSMutableDictionary *)params

                         httpMethod:(NSString *)method;

            @end

            @class MKNetworkOperation;

            I am actually editing the Yahoo example, by replacing the JSON file. I am inserting the code to add data to the NSDictionary in the `currencyRateFor` method in the Yahoo.m class.

            I have the following code there, and still not sure how to save it;
            NSDictionary *valueDic = [[completedOperation …. // not sure how to save it

            Help :( 

          • Shne

            I came up with an idea, which i need to clarify. 

            What if i use
            NSData *valueData = [completedOperation responseData] ;and then convert NSData to NSDictionary ? Will this work ? If its working then it should work for both iOS4 and 5

          • Rob Booth

            I handled this differently.  I added SBJSON (i.e. json-framework : https://github.com/stig/json-framework) to my application then created this class (https://gist.github.com/3132791) to create an NSJSONSerialization class for iOS versions that don’t include it. This way all of the MKNetworkKit checks for the NSJSONSerialization class return correctly.  I had to do this because I post JSON as well MKNetworkKit hides that logic in a category and I didn’t want to override that also.

          • MugunthKumar

            This is interesting. But, moving forward, consider making your app iOS 5 only.
            Mugunth
            Author | Developer | Trainer
            iOS 5 Programming book
            iBooks: http://mk.sg/ibook
            Amazon: http://mk.sg/ios5book

          • Rob Booth

            Tell that to my business owner who wants to continue supporting all of the legacy users who haven’t upgraded to 5.0 yet.

  • Avalanched

    Is there going to be opportunity to set the timeout / operation?

  • Mungbeans

    Is it possible to use this framework in conjunction with :beginBackgroundTaskWithExpirationHandler? 
    If my program starts to download something and then moves to the background how would this framework be used in conjunction with beginBackgroundTaskWithExpirationHandler  to finish the task that had started, and also to start to download other items until the 10 minute timeline is up?

    Thanks

    • Anonymous

      You don’t have to do this explicitly.
      The framework automatically runs all operations in background.

      You start a download, close the app and open again. The download would have progressed more than what it was when you closed.
      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

  • Anthony Janssens

    Hi,
    First off thanks a lot for this, it’s brilliant!
    One thing though. I am trying to use the freezable operations but when I set an operation to freezable the onCompletion and/or onError blocks don’t get executed and this even if I always have a connection. Setting up a proxy I can tell that the operation wen through but I get no feedback. Is this a bug or a limitation? Any workarounds you could suggest?

    Thanks

  • Hi,

    I am very new to ios and xcode.
    I am trying to test download like you did in your example.
    MK Kits are copied to my work space. All the corresponding code and files are copied.

    4. Delete NSAlert+MKNetworkKitAdditions.h file if you are building for iOS.”
    I don’t see that file in your example.zip. So I skipped.

    I see libMKNetworkKit-iOS.a is with red color in “Product” folder.

    But build failed. and get these Apple Mach-O Linker (id) e error.
    Your sample work fine..
    How could I solve this?
    Thanks

    Undefined symbols for architecture i386:
      “_OBJC_METACLASS_$_MKNetworkEngine”, referenced from:
          _OBJC_METACLASS_$_Downloader in Downloader.o
      “_OBJC_CLASS_$_MKNetworkEngine”, referenced from:
          _OBJC_CLASS_$_Downloader in Downloader.o
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

      “_OBJC_METACLASS_$_MKNetworkEngine”, referenced from:
         _OBJC_METACLASS_$_Downloader in Downloader.o
    “_OBJC_CLASS_$_MKNetworkEngine”, referenced from:
       _OBJC_CLASS_$_Downloader in Downloader.o
    ld: symbol(s) not found for architecture i386
    clang: error: linker command failed with exit code 1 (use -v to see invocation)

     

  •  I see one issue at prefix.pch file..
       If  #import “../../MKNetworkKit/MKNetworkKit.h”  will show up with two Mach O error.
    if I change to #import “../../MKNetworkKit-iOS/MKNetworkKit.h” show only one error. But the error is “MKNetworkKit.h” couldn’t find. May be I can’t link those two projects.. Any Idea?

  • How to pause/cancel downloading? Thanks

  • 853112433

    how can i upload a jpeg photo using “addData:forKey”  ,can you please give me a simple demo. thanks!

  • I can block my operation by constantly scrolling my views.
    Does MKNetorkKit run on the main thread?

    • MugunthKumar

      MKNetworkKit returns on main thread

      • To avoid user interaction blocks/pauses download you ca schedule the connection to run in a different run loop.

        Like this:[connection scheduleInRunLoop:[NSRunLoop currentRunLoop]
        forMode:NSRunLoopCommonModes];

        Thanks for this great lib!

  • Tom Carter

    This is very lightweight and easy to use!!!. Can MKNetworkKit also be used to download video files to store locally on iOS 5.0 ? (maybe documents directory) and from there we can use to play the video

    • MugunthKumar

      Yes,
      To a MKNetworkOperation, add a outputStream.
      Your data now gets downloaded to a file.

      The sample code shows you how to do this.

      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

  • Tom Carter

    I am using MKNetworkkit to download Video and images. Can it also be used to download mp3 files? if yes, could I use the method: operationWithURLString:params:httpMethod:

    • MugunthKumar

      Yes you can.
      Attach a downloadStream (addDownloadStream: method) to download directly to disk instead of a NSData pointer if the file size is huge.
      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

  • Secondflying

    How can I set Content-Type to application/json for POST method?
    The code below in my sub-MKNetworkEngine class doesn’t wok.
    Thanks

    MKNetworkOperation *op = [self operationWithPath:SUBMIT_ORDER_URL params:body httpMethod:@”POST”];
    op.postDataEncoding = MKNKPostDataEncodingTypeJSON;Below are log message:

    Request
    ——-
    curl -X POST -H “Accept-Language: en, fr, de, ja, nl, it, es, pt, pt-PT, da, fi, nb, sv, ko, zh-Hans, zh-Hant, ru, pl, tr, uk, ar, hr, cs, el, he, ro, sk, th, id, ms, en-GB, ca, hu, vi, en-us” -H “Content-Type: application/x-www-form-urlencoded; charset=utf-8” “http://192.168.1.100:8080/ChihuoService/rest/orders/” -d “tid=1” -d “number=4”
    2012-03-16 16:57:52.211 testCoreData[2735:fb03] -[MKNetworkOperation operationFailedWithError:] [Line 1176]

    • MugunthKumar

      The encoding type JSON and X-PLIST is not yet implemented in MKNetworkOperation.

  • Tom Carter

    I’m using MKNetworkKit to download audio, video and image files to the iPad’s document directory(using exampleDownloader sample). Even after giving the usesCache to the download engine, the isInCache for imagefromURL comes as false. Can you give some pointers as to what could be the problem? or point me in the right direction incase I’m making a mistake

  • Anybody can provide example code for post json string to server please.

    Thankyou

    • MugunthKumar

      JSON and X-PLIST encoding is not yet implemented.

      • It possible to use external encoder for encode data to json string and send it as HTTP Post body. 

        I mean as normal single json string http request body not (key => value) format ?
        ——————
        operationWithPath: params: 

        op addData: forKey: 
        —————————-

        I found both method still need (key => value) only.

  • Brian

    Great book from you and Rob! Best IOS book I have purchased so far. I have a question on the caching. If I turn on caching my completion blocks get called twice. In most of my calls I would not want the completion block called twice. I would like the cache to get returned and then the network call silently updates the cache or I would like the option to only do the network call once and use the cache until the cache is gone. I could probably solve all of this with a couple of new properties in MKNetworkEngine.h but not sure if that would be the way to go. Any suggestions and pointers on where to put this in the code? 

    • MugunthKumar

      Brian,
      If you silently update the cache without notifying the UI, the UI will have stale data. If that is not a problem in your case you can use the method isCachedResponse in the completionBlock.
      if( ! [completedOperation isCachedResponse]) {

      // this is a live response. Ignore it if your view controller already have data }

      I believe, since MKNetworkKit calls the completionBlock twice, it results in duplicated data (If I assume you are adding the response objects to a NSMutableArray). This should help you to avoid that.
      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

      • Brian

        Most of the data used in my apps is not data that changes frequently. It is historical or pick lists or other types of data.

        I guess what I am looking for is an option to get the live data once from the web and cache it and then only get it live again if the cache is gone. I can always clear the cache if I want, for example each time the application is started. 

        I want to avoid the network calls if I have already retrieved the data but didn’t want to implement my own caching as it is built in to MKNetworkKit.I will add this as an enhancement suggestion to the git project.

        • MugunthKumar

          If most of your data is static (HTML/IMAGES), you can set “Cache Control: max-age=n” where n is time in seconds. (You can probably set this to a very high value (say 7 days). You can set this on your Apache/nginx server config. Not only MKNetworkKit, most intermediate proxy servers also obey these headers and reduce the latency (and thereby the usability) of the app.

          • Brian

            Data is from a variety of web services which retrieve it from various databases. May be unique to a specific user or not. Whether it is cached on server side or not is not applicable to my IOS client. I guess I am looking at something similar to page 320 in your book. The data in the cache would not be stale unless I clear it so it will always retrieve it from the cache.

  • Mik

    Hello Kumar, I’m trying to adopt your great library, but I’m stuck on some problems.  

    1. is it possible to run synchronous, blocking HTTP request?
    2. How can I get to HTTPResponseHeaders – I need to know “Last-Modified” record

    • MugunthKumar

      Synchronous blocking requests arent supported and I don’t have any intention to support it in the near future.

      You can get the response header from the property readonlyResponse on MKNO

      • Mik

        Thanks for your superfast response!

  • Steve McKnight

    MKNetworkKit really looks great. Is it possible to get the cached response / document if there’s no internet connection / offline? Example: I am online and have downloaded a large PDF document which is cached. Two hours later I am offline and I want to read the document. How is this possible? Thank you!

    • MugunthKumar

      Yes it should. But for documents that are downloaded using outputStreams, they won’t be cached.
      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

      • Steve McKnight

        When I am offline MKNetworkKit never reaches the onCompletion – only the onError block. Inside the onError is no chance to get a reference to the cached file. Or am I doing something wrong?

        • MugunthKumar

          Did you enable cache on your Engine?
          You should call [myEngine useCache] to enable MKNetworkKit’s transparent caching.

          • Steve McKnight

             I did enable the caching but when I am offline it only jumps in the onError block. Could this be a bug?

          • MugunthKumar

            I don’t think so. Can you send me a sample project where you could reproduce this?

          • Hey there … I’m getting the same issue. I have [self useCache] … I’m not really doing anything special in my subclass of MKNetworkEngine, though I have increased cacheMemoryCost to 30 … let me know if you would like to see my code.

            PS THANK YOU SO MUCH for the fantastic library

  • Michael

    I think people should be aware that MKNetworkKit looks pretty good on the surface, but the first couple things I tried with it didn’t work. For example, what networking library can’t POST json or xml (without hacking the library or jumping through strange hoops a la setCustomPostDataEncodingHandler:forType:)? Do I really need to set the username/password on every request?

    I’d really like to see this library survive, but it seems almost abandoned at this point considering that such obvious bugs and missing features have gone unaddressed – there are a number of unpulled requests that deal with some of the deal-breaking issues that likely most people are encountering.

    I don’t want to give up on this library so easily so perhaps some kind of status update would help people like me decide what to do.

    Thanks for you hard work.

    • Johnstaniforth

      What are the alternatives?

      • MugunthKumar

        The latest MKNetworkKit supports JSON and xplist encoding.

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

        • Michael

          Thanks for getting that working!

        • Tomson

          Can you give some example codes about POST json request? Thanks.

      • Michael

        The main alternative is probably AFNetworking, but it doesn’t have a few of MKNetworkKit’s most attractive features like operation freezing. I’m not sure how it’s caching compares.

  • Netcode

    how to use reachabilityChangedHandler property of MKNetworkEngine? I am receiving EXC_BAD_ACCESS while trying this: 

    [engine setReachabilityChangedHandler:^(NetworkStatus n) {

                NSLog(@”reachability changed”); //

            }];

  • Tom Carter

    when using addDownloadStream: in an operation with onCompletion block, is it possible to extract the target file path to which the download stream downloaded the file? I need to know this in order to use this downloaded file in the application… 

    • MugunthKumar

      I believe this is how you set the downloadStream.

      [op addDownloadStream:[NSOutputStream outputStreamToFileAtPath:filePath append:YES]];

      If so, you should get the file in the path you specify at filePath.

      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

      • Tom Carter

        Nopes. I need to access the filePath in the onCompletion block:. This block has access to completedOperation right? My question is more on how would I be able to extract the file path from there… 

  • jangelo42

    I’m having a bit of a problem getting going.  I’m getting the following error in my iOS code:
    “_OBJC_CLASS_$_MKNetworkEngine”, referenced from:
          _OBJC_CLASS_$_SunlightServicesEngine in SunlightServicesEngine.o
          _OBJC_CLASS_$_RTCServicesEngine in RTCServicesEngine.o
    ld: symbol(s) not found for architecture i386

    I’ve placed the MKNetworkKIt Folder into my project and have #import MKNetworkKit/MKNetworkKit defined in my pch file.

    what am I missing?

    • jangelo42

       OK solved my own problem.  1.  I reverted from the .85 code in github the .83 branch and 2. removed the folder reference in the included files and placed the files in a group instead.

      • Thanks for posting back your solution. I had the same problem.

  • shayneo

    Has sharedEngine been retired? It doesnt seem to be in the latest git?

  • Bin

    Is there anyway to clean up the disk cache if the response is expired longer than some threshold?

    • MugunthKumar

      Disk cache is expired based on http caching headers.
      You can also use emptyCache method in MKNetworkEngine to empty the complete cache
      Sent from my iPad
      Mugunth
      Author | Developer | Trainer
      Get my iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

  • Cole Joplin

    I have used this framework to do a POST with a user/password, and it works great! Unfortunately, when I use another API that includes the same fields, same values, only I’m using the addFile: the post adds a “/r/n” into the string value, so my auth fails. Is there a way around that?

    • MugunthKumar

      I guess this is a bug.
      A couple others reported this as well.

      I’m working on this now.

      Mugunth
      Author | Developer | Trainer
      iOS 5 Programming book
      iBooks: http://mk.sg/ibook
      Amazon: http://mk.sg/ios5book

  • Headstock67

    Could you please write a beginners step by step showing how to upload a file to a server, complete with a suitable PHP script to handle the server side upload.

  • pitik

    Hi Mugunth,
    FIrst, thanks for sharing such great code.
    I have a small issue: after setting up an “operationWithPath”, setting some params (say for this example: “test”, “printString”), with “httpMethod” set to POST, I am unable to access my params on my php code. If I do: isset($_POST[“printString”]) it returns false and also: “if ($_POST[“printString”] == ‘test’)” fails. I’ve been trying to find where is my issue, but can’t find it.
    To add some info, the request prints as follows: curl -X POST -H “Accept-Language: en,… blah blah… …vi, en-us” “http://myserver/pathToPhp” -d “command=fetch”
    Im running this with iOS 5.1 and latest NKNetworkKit code… 
    Any help would be appreciated.

  • How can I repeat the MKNetworkOperation several times during the failure?

    [operation onCompletion:^(MKNetworkOperation *operation) {
    DLog(@”%@”, operation);
    } onError:^(NSError *error) {
    DLog(@”%@”, error);
    [self enqueueOperation:operation];// not work
    }];

  • Benray1943

    Hi, first thank you for sharing this framework.
    I want to know if I can setPostDataEncoding to “multipart/form-data”.

    • MugunthKumar

      When you call addFile or addData to a operation, I do that automatically for you

  • Van Du Tran

    Hi,

    Is it possible to cancel a currently ongoing request?

    • Daniel

      Yes. You can do [operation cancel] where operation is a MKNetworkOperation object.

  • Slow Tree

    Hi, first of all thank you so much for this framework. I would like to move all my code from ASI to MKNetworkKit I love the design, and I think that It could make my library more elegant and usable. 😉
    There are some cases where I need to call web service using SOAP calls. Could you provide me an example, just few line of codes, on how to properly create a request with a SOAP payload. I don’t understand how to add the POST body. Thanks a lot.

  • Susim Samanta

    Hi,
       I am using your networking kit I am facing followings issues.

     I debugged the thing and found crashing issues in this section.In the section of your code  plz see Fraction Code1 of Kit: [self.dataToBePosted addObject:dict];   NSLog(@”%@”,self.dataToBePosted);I am getting proper data in log(dataToBePosted) but when it comes that linePlease see Fraction Code2 of Kit :  NSLog(@”%@”,self.dataToBePosted);
       [self.request setHTTPBody:[self bodyData]];

     it(dataToBePosted) become nil and crashed .Fraction Code1 of Kit:

    -(void) addData:(NSData*) data forKey:(NSString*) key mimeType:(NSString*) mimeType fileName:(NSString*) fileName {

      

      [self.request setHTTPMethod:@”POST”];

      

      NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:

                            data, @”data”,

                            key, @”name”,

                            mimeType, @”mimetype”,

                            fileName, @”filename”,     

                            nil];

      

      [self.dataToBePosted addObject:dict];  

        NSLog(@”%@”,self.dataToBePosted);

    }Fraction Code2 of Kit :
        if ([self.request.HTTPMethod isEqualToString:@”POST”] || [self.request.HTTPMethod isEqualToString:@”PUT”]) { 
            
            NSLog(@”%@”,self.dataToBePosted);
          [self.request setHTTPBody:[self bodyData]];If any help ….thanks