I am using AWSS3 to upload my media to amazon.
This is how I am doing:
Bool uploaded = NO;
dispatch_async("my.queue.whatever", ^{
NSData *mediaData = UIImagePNGRepresentation(mediaImage);//mediaImage of type uiimage
NSString *pictureName = #"randomstring";
AmazonCredentials *amazonCredentials = [[AmazonCredentials alloc] initWithAccessKey:#"myAccessKey" withSecretKey:#"mySecretKey" withSecurityToken:#"mySessionToken"];
AmazonS3Client *s3Client = [[AmazonS3Client alloc] initWithCredentials:amazonCredentials];
S3PutObjectRequest *s3Request = [[S3PutObjectRequest alloc] initWithKey:pictureName inBucket:#"myPictureBucket"];
s3Request.delegate = self;
//s3Request.contentType = CONTENT_TYPE;
s3Request.cannedACL = [S3CannedACL publicRead];
s3Request.data = mediaData;
[s3Client putObject:s3Request];
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!uploaded);
);
and these are my delegate functions:
-(void)request:(AmazonServiceRequest *)request didCompleteWithResponse:(AmazonServiceResponse *)response
{
uploaded = YES;
}
-(void)request:(AmazonServiceRequest *)request didFailWithError:(NSError *)error{
uploaded = YES;
}
- (void)request:(AmazonServiceRequest *)request didFailWithServiceException:(NSException *)exception{
NSLog(#"didFailWithServiceException %#",[exception description]);
uploaded = YES;
}
- (void)request:(AmazonServiceRequest *)request didSendData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten totalBytesExpectedToWrite:(long long)totalBytesExpectedToWrite{}
-(void)request:(AmazonServiceRequest *)request didReceiveResponse:(NSURLResponse *)response{}
-(void)request:(AmazonServiceRequest *)request didReceiveData:(NSData *)data{}
and when the function didFailWithServiceException is called, it gives me the error: "Request timed out". I can't find anything in google. Need your help!! Thanks
Try to increase the default timeout:
s3Client.timeout = desiredtimeout;
I'm experimenting some problems with the upload operation, it starts to upload but after a couple of seconds the delegate is not called again.
request: didSendData: totalBytesWritten: totalBytesExpectedToWrite:
I don't know if there is some bug in the framework or in the Amazon servers, or it is just some bug in my code.
Related
I never use web API and don't know what i may read about this. I read FAROO Return Values doc, but i don't understand how i may get result-array (or dictionary) in cocoa.
Please anybody give me example or tutorial how to use Faroo API (or other web API) in objective-c.
Thank you.
To use web API and FAROO API in particular i use NSURLConnection class and NSURLConnectionDelegate protocol:
- (IBAction)search:(id)sender {
NSString* requestString = [NSString stringWithFormat:#"http://www.faroo.com/api?q=%#&start=1&length=10&l=ru&src=news&f=xml&YOUR_API_KEY",[searchField stringValue]];
// NSLog(#"str %#",requestString);
NSURL* requestUrl = [NSURL URLWithString:requestString];
NSURLRequest* searchRequest = [NSURLRequest requestWithURL:requestUrl cachePolicy:NSURLRequestReloadRevalidatingCacheData timeoutInterval:60];
[self performSelectorOnMainThread:#selector(startConnectionWithRequest:) withObject:searchRequest waitUntilDone:NO];
}
- (void)startConnectionWithRequest:(NSURLRequest*)request {
NSURLConnection* connection = [[NSURLConnection alloc]initWithRequest:request delegate:self startImmediately:YES];
if (connection) {
//update GUI and do something...
theData = [NSMutableData data];
}
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Receive data");
[theData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSLog(#"Http status code %ld",(long)[httpResponse statusCode]);
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Finish");
//do something with data and update GUI
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSAlert* searchFailedAlert = [NSAlert alertWithError:error];
[searchFailedAlert runModal];
}
One other way of doing things is to declare the missing method yourself as a category of the class in question. This will get the compiler to stop complaining about not finding the method, though of course you'll still need the runtime check you're already doing to avoid actually calling the method. You might also want to wrap such a declaration using availability macros, so that it will be ignored once you do move up to using the 10.5/10.6 SDK and you won't get a different compiler complaint down the line. That would look something like this:
#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4 //ignore when compiling with the 10.5 SDK or higher
#interface NSPropertyListSerialization(MissingMethods)
+ (NSData *)dataWithPropertyList:(id)plist format:(NSPropertyListFormat)format options:(NSPropertyListWriteOptions)opt error:(NSError **)error;
#end
#endif
I have an app which downloads some files from the server in few threads. The problems is that it is giving a heavy load to the CPU (hitting to 80%). What can be done to make it better? I made similar app on Windows with C#, and the cpu usage never goes above 5%.
EDIT: This code has been changed after getting some suggestions below. The problem now is, that the download never reaches 100% when I set [queue setMaxConcurrentOperationCount:6]. If I change the asynchronous NSURLConnection back to sendSynchronous call it works, when I change the above OperationCount to 1, also works.
This is how I add NSOperations to the queue (may be large, like 800).
int chunkId = 0;
for (DownloadFile *downloadFile in [download filesInTheDownload])
{
chunkId = 0;
for (DownloadChunk *downloadChunk in [downloadFile chunksInTheFile])
{
DownloadChunkOperation *operation = [[DownloadChunkOperation alloc] initWithDownloadObject:download
downloadFile:downloadFile downloadChunk:downloadChunk andChunkId:chunkId];
[queue addOperation:operation];
chunkId++;
}
}
#import "DownloadChunkOperation.h"
#import "Download.h"
#import "DownloadFile.h"
#import "DownloadChunk.h"
#interface DownloadChunkOperation()
#property(assign) BOOL isExecuting;
#property(assign) BOOL isFinished;
#end
#implementation DownloadChunkOperation
#synthesize download = _download;
#synthesize downloadFile = _downloadFile;
#synthesize downloadChunk = _downloadChunk;
#synthesize isFinished = _isFinished;
#synthesize isExecuting = _isExecuting;
- (id) initWithDownloadObject:(Download *)download downloadFile:(DownloadFile *)downloadFile downloadChunk:(DownloadChunk *)downloadChunk andChunkId:(uint32_t)chunkId
{
self = [super init];
if (self) {
self.download = download;
self.downloadFile = downloadFile;
self.downloadChunk = downloadChunk;
self.chunkId = chunkId;
}
return self;
}
- (void) start
{
if ([self isCancelled]) {
[self setIsFinished:YES];
[self setIsExecuting:NO];
return;
}
[self setIsExecuting:YES];
[self setIsFinished:NO];
[self.downloadChunk setChunkState:cDownloading];
downloadPath = [[NSString stringWithFormat:#"%#/%#", [self.download downloadFolder], [self.download escapedTitle]] stringByExpandingTildeInPath];
NSURL *fileURL = [[NSURL alloc] initWithString:[self.downloadFile filePath]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fileURL];
NSString *range = [NSString stringWithFormat:#"bytes=%lli-%lli", [self.downloadChunk startingByte], [self.downloadChunk endingByte]];
[request setValue:range forHTTPHeaderField:#"Range"];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
// IMPORTANT! The next line is what keeps the NSOperation alive for the during of the NSURLConnection!
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[connection start];
if (connection) {
NSLog(#"connection established!");
do {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (!self.isFinished);
} else {
NSLog(#"couldn't establish connection for: %#", fileURL);
}
}
- (BOOL) isConcurrent
{
return YES;
}
- (void) connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response
{
receivedData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Not cancelled, receive data.
if (![self isCancelled]) {
[receivedData appendData:data];
self.download.downloadedBytes += [data length];
return;
}
// Cancelled, tear down connection.
[self setIsExecuting:NO];
[self setIsFinished:YES];
[self.downloadChunk setChunkState:cConnecting];
[self->connection cancel];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[self setIsExecuting:NO];
[self setIsFinished:YES];
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *chunkPath = [downloadPath stringByAppendingFormat:#"/%#.%i", [self.downloadFile fileName], self.chunkId];
NSError *saveError = nil;
[receivedData writeToFile:chunkPath options:NSDataWritingAtomic error:&saveError];
if (saveError != nil) {
NSLog(#"Download save failed! Error: %#", [saveError description]);
}
else {
NSLog(#"file has been saved!: %#", chunkPath);
}
[self setIsExecuting:NO];
[self setIsFinished:YES];
[self.downloadChunk setChunkState:cFinished];
if ([self.download downloadedBytes] == [self.download size])
[[NSNotificationCenter defaultCenter] postNotificationName:#"downloadFinished" object:self.download];
}
#end
You should not create threads yourself. Use dedicated API like NSOperationQueue or even GCD directly for this purpose. They know better about hardware limits, virtual cores, etc. and support priority settings.
You shouldn't use +sendSynchronousRequest: either. Wrapping your -downloadChunk method in a dispatch call as suggested by charith won't help you improve performance, as +sendSynchronousRequest: blocks the thread until new data comes in and forces GCD to spawn new threads.
Use the asynchronous API of NSURLConnection using delegate callbacks. You can also wrap your NSURLConnection code inside a NSOperation subclass and use NSOperationQueue to manage the downloads: Using NSURLConnections
If you don't want to write the NSOperation subclass yourself, you can also use a 3rd party framework like AFNetworking.
Try with GCD blocks and global queues. This is the apple recommended way now for concurrency ex:
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
[self downloadChunk:objDownload];
});
I am attempting to write a bit of code that checks the URL of a datasource, then populates an array with objects from that URL. It actually works well, but if there is a problem with the web connection or the address I want to populate the array with data from a bundled file. The issue I am having is that the connection didFailWithError method is never called. I tried passing a simple string but it does not call. I want the app to still function for people who are using ipod touch or are in airplane mode.
connection didReceiveResponse is working without issue.
This is what I'm working with.
- (void)loadListData{
NSLog(#"Loading data from sources");
NSURLRequest *listURLRequest = [NSURLRequest requestWithURL:integerPhoneListURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:1.0];
[[NSURLConnection alloc] initWithRequest:listURLRequest delegate:self];
if (!listConnectFail){
phoneListJSON =[NSData dataWithContentsOfURL:integerPhoneListURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:phoneListJSON waitUntilDone:YES];
} else {
//This will tell us if there is an error loading the file
NSLog(#"File not found on web init from file");
phoneListJSON =[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"contactlist" ofType:#"json"]];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:phoneListJSON waitUntilDone:YES];
}
//Initialize the filtered list with array of customer objects. Based on original data
filteredList = [[NSMutableArray alloc] init];
for (NSDictionary *dict in phoneListOriginal) {
contact *single = [[contact alloc] init];
single.fName = [dict objectForKey:#"fName"];
single.lName = [dict objectForKey:#"lName"];
single.extension = [dict objectForKey:#"extension"];
single.title = [dict objectForKey:#"title"];
single.department = [dict objectForKey:#"department"];
single.cellNumber = [dict objectForKey:#"cellNumber"];
//NSLog(#"%#", single.lName);
[filteredList addObject:single];
}
NSLog(#"Array filteredLIst contains %d records",[filteredList count]); }
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error{
listConnectFail = YES;
NSLog(#"Connection Failed, pulling from file"); }
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
listConnectFail = NO;
NSLog(#"Connection Succeeded, populating from API");
}
I know it is probably something stupid that I am not seeing, but I could use the help to see what I don't
Thanks in advance!
How did you confirm that your delegate did not receive the message? Did you check the log?
Your code seems to assume that 'listConnectFail' will be set immediately after the NSURLConnection's init is done, which is not necessarily the case.
[[NSURLConnection alloc] initWithRequest:listURLRequest delegate:self];
if (!listConnectFail){...}
The NSURLConnection documentation states that 'The delegate will receive delegate messages as the load progresses.'
However, I am not sure about the airplane mode, maybe this particular error can be detected synchronously.
I'm trying to get my iOS app to access files from my local apache server using basic authentication. Everything works fine from the browser and I have to enter my username and password to access an image in the restricted folder. However in the app some strange things are happening.
I make an NSURLConnection to the server (which is all working fine) and the first time my request is made the delegate method - (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge is called. For test purposes I respond with an empty NSURLCredential and obviously the connection fails. However when I make the request again the delegate method isn't called and somehow the image gets downloaded and displayed without any authentication. I'm really confused as to what's going on!
Here is some of the code:
- (IBAction)loginPressed
{
self.username = self.usernameField.text;
self.password = self.passwordField.text;
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://192.168.0.2/secret/favicon.ico"]];
self.connection = [NSURLConnection connectionWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)data
{
[self.data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
self.imageView.image = [UIImage imageWithData:self.data];
self.errorLabel.text = #"";
}
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if ([challenge previousFailureCount] == 0) {
NSURLCredential *newCredential = [NSURLCredential credentialWithUser:self.username password:self.password persistence:NSURLCredentialPersistenceNone];
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
} else {
[challenge.sender cancelAuthenticationChallenge:challenge];
self.errorLabel.text = #"Invalid Username and/or Password";
self.imageView.image = [UIImage imageWithData:[[NSData alloc] init]];
}
}
You should use a different delegate callback, connection:didReceiveAuthenticationChallenge:.
- (void) connection:(NSURLConnection *)connection
didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
if ([challenge previousFailureCount] > 0) {
// Do something, like prompt for credentials or cancel the connection
} else {
NSURLCredential *creds = [NSURLCredential
credentialWithUser:#"someUser"
password:#"somePassword"
persistence:NSURLCredentialPersistenceForSession];
[[challenge sender] useCredential:creds forAuthenticationChallenge:challenge];
}
}
I'm trying to do the following with a modified version of the echo server example that comes with the cocoaasyncsocket library:
1) open a connection to a python script acting as a server
2) send data // works, but delegate doesn't fire
3) receive data back // delegate doesn't fire
4) disconnect // doesn't disconnect, apparently still in my thread
Currently I open a connection in the didFinishLaunchingWithOptions delegate, and then attempt to send data in the didConnectToHost delegate. I then attempt to read data coming back from the client and then disconnect.
I am able to open a connection and send data (which the server verifies as received) but the didWriteDataWithTag delegate never fires. However, the server receive the data. The server then fires back some data, but the didReadData doesn't fire either.
Beside the fact the read/write delegates aren't firing, it seems the way I'm organizing my code is not right, but I'm not sure how this looks in an event-driven system as opposed to run loop (I'm a novice at event-driven stuff + networking). If I have a series of actions whose respective completions are triggered by their delegates, should the delegates be sharing some sort of messages- ie we recieved an "xxx" message, write back "yyy"? I'd prefer to have one function which manages all of this. Is there a canonical way of doing this?
IPhoneConnectTestAppDelegate.m (snippets)
- (void)localConnect {
NSError *error = nil;
if (![asyncSocket connectToHost:#"localhost" onPort:5000 error:&error]) {
DDLogError(#"Error connecting: %#", error);
}
}
- (void)disconnect {
[asyncSocket setDelegate:nil];
[asyncSocket disconnect];
[asyncSocket release];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Setup our socket (GCDAsyncSocket).
dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];
[self localConnect];
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)onSocket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
NSString *output = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
NSLog(#"didReadData: %#", output);
}
- (void)onSocket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(#"didWriteDataWithTag");
}
- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
if(port == 5000)
{
NSString *msg = #"q";
NSData *dataOut = [msg dataUsingEncoding:NSASCIIStringEncoding];
[asyncSocket writeData:dataOut withTimeout:-1 tag:0];
[asyncSocket readDataWithTimeout:-1 tag:0];
[self disconnect];
}
}
tcpserver.py
# TCP server example
import socket, time
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(("", 5000))
server_socket.listen(5)
print "TCPServer Waiting for client on port 5000"
while 1:
client_socket, address = server_socket.accept()
print "I got a connection from ", address
while 1:
data = client_socket.recv(512)
print "Data from client",data
time.sleep(2)
data = "xxx"
print "Sending data to client",data
client_socket.send (data)
break;
I know this is an old question with an already accepted answer, but to clarify for people who find this thread looking for something, the reason the delegate methods didn't get called is because the GCDAsynchSocket start with socket: instead of onsocket: ie:
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
becomes:
- (void) socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
A friend of a friend figured it out for me! We were not able to get GCDAsyncSocket to work properly (connect and write, but not read). AsyncSocket however functions in all 3 respects, and all the delegates work properly.
#import "AsyncSocket.h"
#import "tcp_clientViewController.h"
#implementation tcp_clientViewController
#synthesize socket;
-(IBAction)connect:(id)sender {
NSLog(#"(IBAction)connect");
NSError *error = nil;
if (![socket connectToHost:#"localhost" onPort:5000 error:&error]){
NSLog(#"Error connecting: %#", error);
}
}
-(IBAction)send:(id)sender {
NSLog(#"(IBAction)send");
char bytes[] = "abcd\r\n";
NSData* data = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)];
//NSString *msg = #"xxxxx\r\n";
//NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
[socket writeData:data withTimeout:-1 tag:0];
//NSData *data = [asyncSocket readDataWithTimeout:-1 tag:0];
[data release];
[socket readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:0];
}
- (void)viewDidLoad {
// initialize socket
socket = [[AsyncSocket alloc] initWithDelegate:self];
}
#pragma mark AsyncSocket Delegate Methods
-(void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag {
NSLog(#"socket:%p didWriteDataWithTag:%#", sock, tag);
}
- (void)socket:(AsyncSocket *)sock didWritePartialDataOfLength:(NSUInteger)partialLength tag:(long)tag {
NSLog(#"socket:%p didWritePartialDataOfLength:%# tag:%#", sock, partialLength, tag);
}
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
NSLog(#"socket:%p didConnectToHost:%# port:%hu", sock, host, port);
}
- (void)socketDidSecure:(AsyncSocket *)sock
{
NSLog(#"socket:%p socketDidSecure", sock);
}
- (void)socketDidDisconnect:(AsyncSocket *)sock withError:(NSError *)err
{
NSLog(#"socket:%p socketDidDisconnect withError: %#", sock, err);
}
- (void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
NSString* newStr = [NSString stringWithUTF8String:[data bytes]];
NSLog(#"socket socketDidReadData:%#", newStr);
}
-(IBAction)disconnect:(id)sender { }
#pragma mark View stuff
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {}
- (void)dealloc {
self.socket = nil;
[super dealloc];
}
#end
Try to use local sock for reading commands and to put them in the write command
- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag
{
[sock readDataToData:[AsyncSocket LFData] withTimeout:-1 tag:tag];
}