Custom delegate method doesn't get called - ios

So, I'm following this answer in trying to pass data between two classes in an iOS project without storyboards. I'm trying to abstract all my server calls in a different class, so the ViewControllers don't get too cramped. I have an OfferRequest class, which handles the server requests and declares the protocol:
#protocol OfferRequestDelegate <NSObject>
-(void)addOfferRequest: (OfferRequest *)request dataFromRequest: (NSMutableArray *)data;
#end
#interface OfferRequest : NSObject <LocationManagerDelegate, NSURLConnectionDataDelegate>
#property (nonatomic, weak) id <OfferRequestDelegate> delegate;
#end
The idea is to call addOfferRequest: dataFromRequest in connectionDidFinishLoading, set the data as the result from the request and pass it on to the ViewController.
In OfferRequest.m:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSMutableArray *result = [NSJSONSerialization JSONObjectWithData:receivedData options:kNilOptions error:nil];
[self.delegate addOfferRequest:self dataFromRequest:result];
}
I declare my ViewController as a delegate for the OfferRequest:
#interface CategorySuggestionViewController : UIViewController <OfferRequestDelegate>
Initialize the OfferRequest object and set it's delegate:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
offer = [OfferRequest new];
offer.delegate = self;
}
And then implement the delegate method:
-(void)addOfferRequest:(OfferRequest *)request dataFromRequest:(NSMutableArray *)data {
NSLog(#"received data = %#", data);
}
But it never gets called. What am I missing ?

try this...
your OfferRequest class like below i have given name it as connectionClass
connectionClass.h
#protocol connectionDelegate <NSObject>
-(void)connectionSucceed:(NSData *)data;
-(void)connectionFailed:(NSError *)error;
#end
#import <Foundation/Foundation.h>
#interface connectionClass : NSObject
{
id<connectionDelegate> delegate;
NSMutableData *receivedData;
NSString *encodedString;
NSMutableURLRequest *theRequest;
NSURL *url;
NSString *length;
NSURLConnection *Connect;
}
#property(nonatomic, retain) id<connectionDelegate> delegate;
#property(nonatomic, retain) NSMutableData *receivedData;
- (void)connectionWithURL:(NSString *)URL;
#end
connectionClass.m
#import "connectionClass.h"
#implementation connectionClass
#synthesize delegate, receivedData;
- (void)connectionWithURL:(NSString *)URL
{
url=[[NSURL alloc] initWithString:[self urlencode:URL]];
theRequest= [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
[theRequest setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
length = [NSString stringWithFormat:#"%lu", (unsigned long)[URL length]];
[theRequest setValue:length forHTTPHeaderField:#"Content-Length"];
[theRequest setHTTPMethod:#"POST"];
[theRequest setHTTPBody:[URL dataUsingEncoding:NSUTF8StringEncoding]];
Connect = [NSURLConnection connectionWithRequest:theRequest delegate:self];
if (Connect)
{
self.receivedData = [NSMutableData data];
}
else
{
NSError *error;
[self.delegate connectionFailed:error];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.receivedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.receivedData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.delegate connectionSucceed:self.receivedData];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self.delegate connectionFailed:error];
}
-(NSString *) urlencode: (NSString *) string
{
encodedString = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)string, NULL, (CFStringRef)#"", kCFStringEncodingUTF16));
return encodedString;
}
#end
don't forget to import your connectionclass and delegate
#interface yourclass : UIViewController<connectionDelegate>
Initialize the OfferRequest object and set it's delegate:
-(void)viewWillAppear:(BOOL)animated
{
connection = [[connectionClass alloc]init];
connection.delegate = self;
[connection connectionWithURL:[NSString stringWithFormat:#"pass your url here"]];
}
The delegate method will have your values
-(void)connectionSucceed:(NSData *)data
{
NSError *error;
self.dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];
//nslog your data
}
//Connection failure
-(void)connectionFailed:(NSError *)error
{
//handle error message
}

Ok, I don't know where the problem exactly was, but what I did to fix it, was to create a new init method, where I pass the delegate:
-(instancetype)initWithDelegate: (id<OfferRequestDelegate>) delegate {
self = [super init];
if (self) {
self.delegate = delegate;
}
return self;
}
So I initialize the OfferRequest object in the VC and pass self and now it works.

I guess delegate should be a pointer object and not the object.
It may be help you
#property (nonatomic, weak) NSObject <OfferRequestDelegate> *delegate;
and make should your delegate is been set, i.e. make sure your code below is getting called.
[self.delegate addOfferRequest:self dataFromRequest:result];

Related

Using NSURLSession inside NSURLProtocol

I'm trying to create a transparent NSURLProtocol for http:// and https:// connections using NSURLSession. However at the moment, even though the completion handler is being run, URL requests with the app (UIWebView) are coming back blank. Does anybody have any ideas? Code is below:
#import "MyURLProtocol.h"
// AppDelegate
#import "AppDelegate.h"
static NSString * const MyURLProtocolHandledKey = #"MyURLProtocolHandledKey";
#interface MyURLProtocol () <NSURLConnectionDelegate,NSURLSessionDelegate>
#property (nonatomic, strong) NSURLConnection *connection;
#property (nonatomic, strong) NSMutableData *mutableData;
#property (nonatomic, strong) NSURLResponse *response;
#end
#implementation MyURLProtocol
+(BOOL)canInitWithRequest:(NSURLRequest*)request
{
if ([NSURLProtocol propertyForKey:MyURLProtocolHandledKey inRequest:request])
return NO;
NSString *scheme = request.URL.scheme.lowercaseString;
return [scheme isEqualToString:#"http"] || [scheme isEqualToString:#"https"];
}
+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
-(void)startLoading
{
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:#"MyURLProtocolHandledKey" inRequest:newRequest];
NSURLRequest *request = newRequest;
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
completionHandler:
^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
NSLog(#"There was an error");
}
NSLog(#"Completiio handler ran");
self.mutableData = [NSMutableData dataWithData:data];
self.response = response;
}];
[task resume];
}
- (void) stopLoading {
[self.connection cancel];
self.mutableData = nil;
}
// Delegate stuff
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
#end
Your code is using NSURLConnection delegates to pass data back to the caller, e.g. connectionDidFinishLoading:.
To fix this:
Replace these with NSURLSession delegate methods.
Create and retain a custom session whose delegate is your protocol class instance; the shared session doesn't have a delegate, so it won't call your class's delegate methods.
Remove the callback block so that the delegate method for request completion will be called correctly.

iOS NSError/NSDictionary for callbacks

I am developing a framework which requires error callbacks. I have used delegate methods to give error callbacks to the users(developer) of the framework. Can I use NSError to indicate error details in the delegate method or simply use NSDictionary instead ? Are there any memory issues concerned here?
Instead of delegate methods, you should use blocks with proper error handling, something like this:
Interface:
typedef void(^ResultBlock)(id result, NSError *error);
extern NSString * const DummyErrorDomain;
enum{
DummyErrorReason1,
DummyErrorReason2
};
#interface Dummy : NSObject
-(void)doSomething:(ResultBlock)resultBlock;
#end
Implementation with async NSURLConnection:
NSString * const DummyErrorDomain = #"DummyErrorDomain";
#interface Dummy ()
#property (strong) ResultBlock resultBlock;
#property NSURLConnection *connection;
#property NSMutableData *responseData;
#end
#implementation Dummy
-(void)doSomething:(ResultBlock)resultBlock
{
self.resultBlock = resultBlock;
self.responseData = [[NSMutableData alloc] init];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:#"dummyURL"]];
self.connection = [[NSURLConnection alloc]initWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
self.resultBlock(nil,error);
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
self.resultBlock(self.responseData, nil);
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
[self.responseData appendData:data];
}
#end
Usage:
-(void)usage
{
Dummy *dummy = [[Dummy alloc] init];
[dummy doSomething:^(id result, NSError *error) {
if(result){
// everything went fine
}else{
// error handling
}
}];
}

xcode Finding memory leaks with Instruments

I have an iOS project with ARC enabled and i'm using Leaks instrument to find leaks.
i have one leak in this line of code and i don't understand why it's a leak :
[self.activeDownload appendData:data];
this is the code of the class
#interface IconDownloader ()
#property (nonatomic, strong) NSMutableData *activeDownload;
#property (nonatomic, strong) NSURLConnection *imageConnection;
#end
#implementation IconDownloader
#synthesize url = _url;
#synthesize activeDownload = _activeDownload;
#synthesize imageConnection = _imageConnection;
- (void)startDownload
{
self.activeDownload = [NSMutableData data];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:self.url]];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
self.imageConnection = conn;
}
- (void)cancelDownload
{
[self.imageConnection cancel];
self.imageConnection = nil;
self.activeDownload = nil;
self.completionHandler = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data]; // leak
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
self.activeDownload = nil;
self.imageConnection = nil;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if (self.completionHandler) {
self.completionHandler(self.activeDownload);
}
self.imageConnection = nil;
}

NSInvalidArgumentException in sending POST request to HTTP

I'm writing simple code which is sending me response from http server after sending a POST request to it but if I try moving everything to another file XCode shows me this error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
Here are the two files I'm using to make this work:
#import "HTTPRequestHandler.h"
#interface HTTPRequestHandler ()
#property (strong, nonatomic) NSURL *requestURL;
#property (strong, nonatomic) NSData *httpBody;
#property (strong, nonatomic) NSMutableData *responseData;
#end
#implementation HTTPRequestHandler
- (id)initWithURL:(NSString *)url body:(NSString *)body
{
if (self = [super init]) {
self.requestURL = [[NSURL alloc] initWithString:url];
self.httpBody = [body dataUsingEncoding:NSUTF8StringEncoding];
}
return self;
}
- (void)makeConnectionWithRequest
{
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:self.requestURL];
[request setHTTPMethod:#"POST"];
[request setHTTPBody:self.httpBody];
[NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"Dane doszły 1");
[self.responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"Dane doszły 2");
[self.responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Dane doszły 3");
NSDictionary *recievedData = [NSJSONSerialization JSONObjectWithData:self.responseData options:kNilOptions error:nil];
NSLog(#"%#", [recievedData description]);
}
#end
and the second one:
#import "ViewController.h"
#import "HTTPRequestHandler.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
HTTPRequestHandler *request = [[HTTPRequestHandler alloc] initWithURL:#"http://own-dev1.railwaymen.org:4006/api/get_grant_key"
body:#"email=vergun#gmail.com&password=password"];
[request makeConnectionWithRequest];
}
#end
Okey, got it! Just forgot self.responseData = [NSMutableData data];

NSUrlConnection doesnt seem to be working,

I'm trying to use googletts converted and seem to be running into trouble. I think I made the class correctly in terms of structure. But I dont think the NSURLConnection is returning any useful data. Can someone please help me check if its working and if not why?
In the connectiondidfinishloading section I am checking download length
NSLog(#"hmmmm %lu", (unsigned long)[downloadedData length])
which is returning 0. Thats why I think its not working.
The goal is to have the app speak what is downloaded
Thanks!!!
I just have a button in my view controller that launches everything
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import "RJGoogleTTS.h"
#interface ViewController : UIViewController <CLLocationManagerDelegate>
#property (weak, nonatomic) IBOutlet UILabel *userLabel;
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) CLGeocoder *geoCoder;
#property (strong, nonatomic) RJGoogleTTS *googleTTS;
- (IBAction)geoCodeLocation:(id)sender;
- (IBAction)rjGoogleButton:(id)sender;
#end
here is the implementation file
- (IBAction)rjGoogleButton:(id)sender {
googleTTS = [[RJGoogleTTS alloc]init];
[googleTTS convertTextToSpeech:#"How are you today user?"];
}
RJGoogleTTS.h
#import <Foundation/Foundation.h>
#protocol RJGoogleTTSDelegate <NSObject>
#required
- (void)receivedAudio:(NSMutableData *)data;
- (void)sentAudioRequest;
#end
#interface RJGoogleTTS : NSObject {
id <RJGoogleTTSDelegate> delegate;
NSMutableData *downloadedData;
}
#property (nonatomic, retain) id <RJGoogleTTSDelegate> delegate;
#property (nonatomic, retain) NSMutableData *downloadedData;
- (void)convertTextToSpeech:(NSString *)searchString;
#end
.m
#import "RJGoogleTTS.h"
#import <AVFoundation/AVFoundation.h>
#implementation RJGoogleTTS
#synthesize delegate, downloadedData;
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (void)convertTextToSpeech:(NSString *)searchString {
NSString *search = [NSString stringWithFormat:#"http://translate.google.com/translate_tts?q=%#", searchString];
search = [search stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
NSLog(#"Search: %#", search);
self.downloadedData = [[NSMutableData alloc] initWithLength:0];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:search]];
[request setValue:#"Mozilla/5.0" forHTTPHeaderField:#"User-Agent"];
NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
[delegate sentAudioRequest];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"did you receive response user");
[self.downloadedData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"did you receive data user");
[self.downloadedData appendData:data];
// AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc]initWithData:downloadedData error:nil];
// [audioPlayer play];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Failure");
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"it worked user!!!");
[delegate receivedAudio:self.downloadedData];
NSLog(#"hmmmm %d", [self.downloadedData length]);
// NSString *txt = [[NSString alloc] initWithData:downloadedData encoding: NSASCIIStringEncoding];
// NSLog(#"%#hello",txt);
}
#end
Remember that this is happening asynchronously. You set the size of downloadedData to 0 after your call the NSURLConnection.
Move:
self.downloadedData = [[NSMutableData alloc] initWithLength:0];
before your call to NSURLConnection.
There's nothing wrong with your NSURLConnection methods. Your search string is wrong. It should be:
NSString *search = [NSString stringWithFormat:#"http://translate.google.com/translate_tts?tl=en&q=%#",searchString];
You didn't start the URLConnection. Change [[NSURLConnection alloc] initWithRequest:request delegate:self]; like this [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];

Resources