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];
Related
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];
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
}
}];
}
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;
}
I am writing a simple code, in which I am using Google API for translation services, but I am getting the following error:
Connection failed: Error Domain=NSURLErrorDomain Code=-1000 "bad URL" UserInfo=0x176c80a0 {NSUnderlyingError=0x175c8d00 "bad URL", NSLocalizedDescription=bad URL}
This is the code I have written:
#import "ViewController.h"
#import"SBJson.h"
#interface ViewController ()
#property (strong, nonatomic) IBOutlet UITextField *textfield;
#property (strong, nonatomic) IBOutlet UIButton *go;
#property (strong, nonatomic) IBOutlet UITextView *textview;
- (IBAction)translate:(id)sender;
#property (strong, nonatomic) NSMutableArray *translations;
#property (strong, nonatomic)NSString *_lastText;
#property (nonatomic, copy) NSString * lastText;
#end
#implementation ViewController
#synthesize lastText = _lastText;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//Initializing the translation array
_translations = [[NSMutableArray alloc] init];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)performTranslation {
responseData = [[NSMutableData data] init ];
NSString *langString = #"en|ja";
NSString *textEscaped = [_lastText
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *langStringEscaped = [langString
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
//My_Key=Google generated key
NSString *url = [NSString stringWithFormat:#"https://www.googleapis.com/language/translate/v2?
key={My_key}&source=en&target=de&q=%#",textEscaped];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (IBAction)translate:(id)sender {
[_translations removeAllObjects];
[_textfield resignFirstResponder];
_go.enabled=NO;
self.lastText = _textfield.text;
[_translations addObject:_lastText];
_textview.text = _lastText;
[self performTranslation];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
_textview.text = [NSString stringWithFormat:#"Connection failed: %#", [error description]];
_go.enabled = YES;
NSLog([NSString stringWithFormat:#"Connection failed: %#", [error description]]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *responseString = [[NSString alloc] initWithData:responseData
encoding:NSUTF8StringEncoding];
NSMutableDictionary *luckyNumbers = [responseString JSONValue];
if (luckyNumbers != nil) {
NSDecimalNumber * responseStatus = [luckyNumbers objectForKey:#"responseStatus"];
if ([responseStatus intValue] != 200) {
_go.enabled = YES;
return;
}
NSMutableDictionary *responseDataDict = [luckyNumbers objectForKey:#"responseData"];
if (responseDataDict != nil) {
NSString *translatedText = [responseDataDict objectForKey:#"translatedText"];
[_translations addObject:translatedText];
self.lastText = translatedText;
_textview.text = [_textview.text stringByAppendingFormat:#"\n%#", translatedText];
_go.enabled = YES;
}
}
}
#end
The problem is like it says. The URL has been generated incorrectly. Try:
NSString * source = #"en";
NSString * target = #"ja";
NSString * key = #"YOUR-KEY";
NSString * url = [NSString stringWithFormat:#"https://www.googleapis.com/language/translate/v2?key=%#&source=%#&target=%#",key,source,target];
and see what response you get.
You can just use FGTranslator. Simple.
FGTranslator *translator = [[FGTranslator alloc] initWithGoogleAPIKey:#"your_google_key"];
[translator translateText:#"Bonjour!"
completion:^(NSError *error, NSString *translated, NSString *sourceLanguage)
{
if (error)
NSLog(#"translation failed with error: %#", error);
else
NSLog(#"translated from %#: %#", sourceLanguage, translated);
}];
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];