Pergunta

I need to make a connection to my server to get some JSON data and I have to support both iOS 6 and iOS 7.

Should I create two classes? One with NSURLSession for iOS 7 and one with NSURLConnection for iOS 6? Or should I just use NSURLConnection for both of them?

Foi útil?

Solução

What benefit would you gain by creating two separate classes that do essentially the same thing? If you can't use NSURLSession because it's only supported in iOS 7, and you can get the same functionality using NSURLConnection, which works in both, then just use NSURLConnection. You will have less code to maintain.

Outras dicas

Great question. In fact I had the same question and researched it quite a bit and I think this is a good place to use a protocol (a.k.a. interface in other languages). This is based off of the quote "Program to an interface, not an implementation" from the famous "Gang of Four" Patterns Book. I think it's best to try and code for the future so I never get hammered if they decide to deprecate something (which isn't the case here, but you never know).

Instead of writing classes, write a protocol that defines the methods you want to use and then create 2 different classes that implement those methods. In your app you would make a pointer that can point to any class that implements all of that protocols methods and then each implementing class can use whatever frameworks/libraries/other code they want to make that happen.

As an example, you could create a Server protocol like this:

// Server.h
@protocol Server <NSObject>
@required
- (void)callService:(NSString *)service withData:(NSData *)data;
@end

and then create a RestServer class like this:

// RestServer.h
#import "Server.h"
@interface RestServer : NSObject <Server>
@end 

// RestServer.m
#import "RestServer.h"
@implementation RestServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using REST
}
@end

and then create another class like SoapServer:

// SoapServer.h
#import "Server.h"
@interface SoapServer : NSObject <Server>
@end 

// SoapServer.m
#import “SoapServer.h"
@implementation SoapServer
- (void)callService:(NSString *)service withData:(NSData *)data {
// Code using SOAP
}
@end

Code your main app to just use a pointer to the interface and now you can swap classes without having to change your main code:

// SomeViewController.m
#import “Server.h”
#import “RestServer.h”
#import “SoapServer.h”
…
- (void)someMethod() {
    id<Server> myServer;

    if ([self shouldIUseSoap])
        myServer = [[SoapServer alloc] init];
    else
        myServer = [[RestServer alloc] init];

    [myServer callService:@"loginUser" withData:[self getData]];
}

Now you can change server classes whenever you want and never have to go hunt down all the places in your code where you make calls to callService:withData:. THIS IS THE BENEFIT OF PROGRAMMING TO INTERFACES!

I used Rest vs Soap because I figured people newer to Objective-C might understand that better, but in your case you’d maybe have a ConnectionServer vs SessionServer or something like that.

Another good read on programming to interfaces/protocols can be found here: https://stackoverflow.com/a/384067/504873

If you have to use NSURLCredentialPersistenceForSession if you have to get into a Windows Authentication network...then using NSURLConnection will create multiple problems for you. I'm going through the pain right now and have come to the conclusion that I need both to support iOS 7. Basically, if you use NSURLConnection and willSendRequestForAuthenticationChallenge, you will find that in iOS 7, your session will end with a mind of it's own (seems like a 30 second mind span). So if you have to persist a credential to access more SOAP or whatever, welcome to the terror dome! I will report back to you with code if I find a smooth solution.

At time of writing, NSURLConnection has been deprecated in OS X 10.11 and iOS 9.0 but my Apps need to support OS X 10.7 and iOS 6. So now you HAVE to use NSURLSession for ongoing projects BUT also support the now deprecated NSURLConnection class for supported legacy OS releases!

I would these days vote for TenaciousJay solution with Compiler warning suppression around the NSURLConnection class implementation.

#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
       /* NSURLConnection code here */
#pragma GCC diagnostic pop

The benefit you would you gain by creating two separate classes that do essentially the same thing is that you can eventually CUT off the old, deprecated solution when you can finally drop support for legacy OS releases.

My code decision to use one class or the other would not be based upon some class property but on the result of a Macro like:

#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)

for iOS or for OS X:

NSString *systemVersion = nil;
        if ([[NSProcessInfo processInfo] respondsToSelector:NSSelectorFromString(@"operatingSystemVersion")]) {
            NSOperatingSystemVersion operatingSystemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
            systemVersion       = [NSString stringWithFormat:@"%ld.%ld.%ld", (long)operatingSystemVersion.majorVersion, (long)operatingSystemVersion.minorVersion, (long)operatingSystemVersion.patchVersion];
        } else {
            SInt32 versionMajor=0, versionMinor=0, versionPatch=0;
#pragma GCC diagnostic push 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
            Gestalt(gestaltSystemVersionMajor, &versionMajor);
            Gestalt(gestaltSystemVersionMinor, &versionMinor);
            Gestalt(gestaltSystemVersionBugFix, &versionPatch);
#pragma GCC diagnostic pop
            systemVersion       = [NSString stringWithFormat:@"%ld.%ld.%ld", (long)versionMajor, (long)versionMinor, (long)versionPatch];
        }
        NSLog(@"[Line %d] %s OS X Runtime Version: '%@'", __LINE__, __PRETTY_FUNCTION__, systemVersion);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top