Skip to content

Commit

Permalink
- Added AFNetworking using CocoaPods, JBMessage.
Browse files Browse the repository at this point in the history
  • Loading branch information
Josip Bernat committed Mar 26, 2014
1 parent 233b2cc commit 572145d
Show file tree
Hide file tree
Showing 2 changed files with 384 additions and 0 deletions.
123 changes: 123 additions & 0 deletions JBMessage/JBMessage/JBMessage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// VCMessage.h
// VectorChat
//
// Created by Josip Bernat on 25/03/14.
// Copyright (c) 2014 Josip-Bernat. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef NSString *JBHTTPMethod;

extern JBHTTPMethod const JBHTTPMethodGET;
extern JBHTTPMethod const JBHTTPMethodPOST;
extern JBHTTPMethod const JBHTTPMethodPUT;
extern JBHTTPMethod const JBHTTPMethodDELETE;

/**
* Response block object can be a single model or a collection depending on the message.
*/
typedef void (^JBResponseBlock)(id responseObject, NSError *error);

/**
* Upload block object containing information about upload progress. Can be called multiple times during the upload.
*/
typedef void (^JBUploadBlock)(NSUInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite);

@interface JBMessage : NSOperation

/**
* Response block to be called once the request finishes.
*/
@property (copy) JBResponseBlock responseBlock;

/**
* Upload block object called when upload sends bytes. Can be called multiply times during the upload.
*/
@property (copy) JBUploadBlock uploadBlock;

/**
* Action for the request, i.e login.php.
*/
@property (nonatomic, copy) NSString *action;

/**
* HTTP method for the request. Default is JBHTTPMethodPOST.
*/
@property (nonatomic, readwrite) JBHTTPMethod httpMethod;

/**
* Determents whether response block should be called on main queue or not. Setting to NO enables you to do heavy parsing on background queue. Default is YES.
*/
@property (nonatomic, readwrite) BOOL shouldCompleteOnMainQueue;

/**
* A file URL for the multipart request.
*/
@property (nonatomic, copy) NSURL *fileURL;

/**
* A filename field used in multpart request. Default is "filename".
*/
@property (nonatomic, copy) NSString *filename;

/**
* Parameters to be send in the request.
*/
@property (nonatomic, strong, readonly) NSDictionary *parameters;

#pragma mark - URL Registration

/**
* Register baseUrl in order to enable request execution. The easiest way is to call it directly from application:didFinishLaunchingWithOptions:.
*
* @param baseUrl Url to register, i.e. http://example.com/api/.
*/
+ (void)registerBaseUrl:(NSString *)baseUrl;

#pragma mark - Initialization

/**
* Initializes the message with parameters
*
* @param parameters Web service parameters to be sent.
* @param responseBlock Response callback. Will contain parsed objects depending on the message or an error if there was one.
*
* @return an instance of VCMessage
*/
+ (instancetype)messageWithParameters:(NSDictionary *) parameters
responseBlock:(JBResponseBlock) responseBlock;

/**
* Initializes the message with parameters
*
* @param parameters Web service parameters to be sent.
* @param responseBlock Response callback. Will contain parsed objects depending on the message or an error if there was one.
*
* @return an instance of VCMessage
*/
- (id)initWithParameters:(NSDictionary *)parameters
responseBlock:(JBResponseBlock) responseBlock;

#pragma mark - Parsing Response
/**
* Parses the raw response from the server and returns a callback.
*
* @param rawResponse Raw server response.
* @param error Error generated by parsing.
*
* @return returns RawResponse if JSON parsing fails by default. Override in subclasses to return other object types.
*/
- (id)parseResponse:(id)rawResponse error:(NSError **) error;

@end

@interface JBMessage (JBMessageCenter)

/**
* Enqueues message on message center and starts server communication. Uses shared operationQueue. Override this method in your subclass in case you need to use some other operation queue.
*/
- (void)send;

@end
261 changes: 261 additions & 0 deletions JBMessage/JBMessage/JBMessage.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,261 @@
//
// VCMessage.m
// VectorChat
//
// Created by Josip Bernat on 25/03/14.
// Copyright (c) 2014 Josip-Bernat. All rights reserved.
//

#import "JBMessage.h"
#import "AFHTTPRequestOperationManager.h"

JBHTTPMethod const JBHTTPMethodGET = @"GET";
JBHTTPMethod const JBHTTPMethodPOST = @"POST";
JBHTTPMethod const JBHTTPMethodPUT = @"PUT";
JBHTTPMethod const JBHTTPMethodDELETE = @"DELETE";

@interface JBMessage () {

BOOL _isCancelled;
BOOL _isFinished;
BOOL _isExecuting;
}

@property (nonatomic) UIBackgroundTaskIdentifier backgroundTaskIdentifier;
@property (nonatomic, strong) NSDictionary *parameters;

@end

@implementation JBMessage

#pragma mark - Memory Management

- (void) dealloc {
_responseBlock = nil;
_uploadBlock = nil;
}

#pragma mark - URL Registration

static NSString *baseUrlString = nil;
+ (void)registerBaseUrl:(NSString *)baseUrl {

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
baseUrlString = baseUrl;
});
}

#pragma mark - Initialization

+ (instancetype)messageWithParameters:(NSDictionary *) parameters
responseBlock:(JBResponseBlock) responseBlock {

JBMessage *message = [[self alloc] initWithParameters:parameters
responseBlock:responseBlock];
return message;
}

- (id)initWithParameters:(NSDictionary *)parameters
responseBlock:(JBResponseBlock)responseBlock {

if (self = [super init]) {

self.parameters = parameters;
self.responseBlock = responseBlock;

_filename = @"filename";
_fileURL = nil;
_httpMethod = JBHTTPMethodPOST;
_shouldCompleteOnMainQueue = YES;
}

return self;
}

#pragma mark - Background Task

- (void)beginBackgroundTask {

self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];
}

- (void)endBackgroundTask {

[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier];
self.backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}

#pragma mark - Operations

-(void) start {

_isExecuting = YES;
_isFinished = NO;

[self executeRequest];
}

- (void) finish {
[self endBackgroundTask];
}

- (void) cancel {
_isCancelled = YES;
}

- (BOOL) isConcurrent {
return YES;
}

- (BOOL) isExecuting {
return _isExecuting;
}

- (BOOL) isFinished {
return _isFinished;
}

- (void)operationDidFinish {

if (!_isExecuting) return;
[self willChangeValueForKey:@"isExecuting"];
_isExecuting = NO;
[self didChangeValueForKey:@"isExecuting"];

[self willChangeValueForKey:@"isFinished"];
_isFinished = YES;
[self didChangeValueForKey:@"isFinished"];

[self finish];
}

#pragma mark - Executing Request

- (void)executeRequest {

__block NSError *uploadError = nil;

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

__weak id this = self;

NSMutableURLRequest *request = nil;

NSString *urlString = [NSString stringWithFormat:@"%@%@", baseUrlString, self.action];
if (self.httpMethod == JBHTTPMethodGET || !self.fileURL) {

NSError *error = nil;
request = [manager.requestSerializer requestWithMethod:self.httpMethod
URLString:urlString
parameters:self.parameters
error:&error];
#ifdef DEBUG
if (error) {
NSLog(@"Error while creating NSMutableRequest: %@", error);
}
#endif
}
else {

request = [manager.requestSerializer multipartFormRequestWithMethod:self.httpMethod
URLString:urlString
parameters:[self parameters]
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {

__strong JBMessage *strongThis = this;
[formData appendPartWithFileURL:strongThis.fileURL
name:strongThis.filename
error:&uploadError];
} error:nil];
}


AFHTTPRequestOperation *operation = [manager HTTPRequestOperationWithRequest:request
success:^(AFHTTPRequestOperation *operation, id responseObject) {

__strong JBMessage *strongThis = this;
[strongThis receivedResponse:responseObject error:nil];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {

__strong JBMessage *strongThis = this;
[strongThis receivedResponse:nil error:error];
}];


[operation setUploadProgressBlock:self.uploadBlock];

[manager.operationQueue addOperation:operation];
}

#pragma mark - Handling Response

- (void)receivedResponse:(id)result error:(NSError *)error {

NSError *parseError = nil;
id parsedObject = nil;

if (result && !error) {
parsedObject = [self parseResponse:result error:&parseError];
error = parseError;
}

if (_shouldCompleteOnMainQueue) {
//return response on the main queue
dispatch_async(dispatch_get_main_queue(), ^{
self.responseBlock(parsedObject, error);
});
}
else {
self.responseBlock(parsedObject, error);
}

[self operationDidFinish];
}


- (id)parseResponse:(id)rawResponse error:(NSError *__autoreleasing *)error{

if ([rawResponse isKindOfClass:[NSData class]]) {

NSError *jsonError = nil;
id response = [NSJSONSerialization JSONObjectWithData:rawResponse
options:0
error:&jsonError];
*error = jsonError;

#ifdef DEBUG
if(jsonError) {
NSLog(@"%@, %@", [jsonError localizedDescription], [[NSString alloc] initWithData:rawResponse encoding:NSUTF8StringEncoding]);
}
#endif
return response;
}
return rawResponse;
}

@end

@implementation JBMessage (VCMessageCenter)

+ (NSOperationQueue *)sharedQueue {

static NSOperationQueue *queue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
});

return queue;
}

- (void)send {

[[[self class] sharedQueue] addOperation:self];
}

@end

0 comments on commit 572145d

Please sign in to comment.