iOS FTP Upload with SCRFTPRequest on ARC - iphone

Hy Everybody, i am using SCRFTPRequest, https://github.com/Hackmodford/SCRFTPRequest to upload a file on a FTP server, i've used it before, it worked great, but now i have a project that is with ARC, the API was recoded to ARC a couple of days ago.
I have a crash, i don't know why, it crashes without any error message after startRequest, the whole function gets executed, including startUploadRequest. I really don't know why it crashes. I've tested on iPAD 1 with 5.0 and iPad 3 with 6.1.
I've tried with other files, same problem, the file is created on the FTP server with the correct name but the size is 0 Kb.
filePath = [[NSBundle mainBundle] pathForResource:#"Spiriva Mentiones Legales" ofType:#"pdf"];
SCRFTPRequest *ftpRequest = [[SCRFTPRequest alloc] initWithURL:[NSURL URLWithString:#"ftp://ftp.belersoft.ro/"]
toUploadFile:filePath];
ftpRequest.username = #"user";
ftpRequest.password = #"pass";
ftpRequest.delegate = self;
ftpRequest.customUploadFileName = [modifiedPathWithXLS lastPathComponent];
[ftpRequest startRequest];
I have implemented all the Delegate Callbacks, only will ftpRequestWillStart gets called

In case anyone else having the 'zero-byte file upload' issue that needs help with this, try replacing
[ftpRequest startRequest];
with
[ftpRequest startAsynchronous];
And add the following delegate method to your code:
- (void)ftpRequest:(SCRFTPRequest *)request didChangeStatus:(SCRFTPRequestStatus)status
(note the difference between the method name versus the one listed in the SCRFTPRequest docs.)
I'm not familiar enough with this library yet to be comfortable changing the library itself, but adjusting the delegate method name and using asynchronous worked for me.

use [ftpResuest startAsynchronous]

Related

Photomania- Stanford Paul Hegarty's class

is there something wrong with core data for xcode 4.3.2
I'm following the Stanford Paul Hegarty class for ios 5.0
doing the core data walkthrough (Video 14 Core data demo)
I downloaded the file here
I ran it in xcode 4.3.2 but the core data doesn't seem to work because the entries in the tableview do not appear.
I tried to run it in another computer with xcode 4.2 and ios 5.0
it's working perfectly
anybody who encountered the same problem? I'm pretty sure that xcode is at fault.
Interesting. I am having the same problems and I am also using XCode 4.3, but just thought it was because of the Flickr license that you need and which I don't have. (In FlickAPIKey.h, there is a #define FlickrAPIKey #"" and you won't download anything if you don't have that key.)
Update: I got myself a Flickr API key (you can just get one from their website) and tried the Photomania App on XCode 4.3: it works like a charm, so it looks like XCode is not your problem here. (Although on occasion I found that I had to stop and restart XCode to get rid of a strange bug or compiler error.) Anyway, maybe it is an idea to delete the data first before you try again: Just delete the App before you run it and the database file will get deleted as well.
Paul Hegarty after his class, has published an update version of his code which have a call to SAVE the CoreData database! This may be the reason why your CoreData informations doesn't persist.
His update note was:
// should probably saveToURL:forSaveOperation:(UIDocumentSaveForOverwriting)completionHandler: here!
// we could decide to rely on UIManagedDocument's autosaving, but explicit saving would be better
// because if we quit the app before autosave happens, then it'll come up blank next time we run
// this is what it would look like (ADDED AFTER LECTURE) ...
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
So, you have to Add the 'document saveToURL' line in the 'fetchFlickrDataInDocument' function like this:
- (void)fetchFlickrDataIntoDocument:(UIManagedDocument *)document
{
dispatch_queue_t fetchQ = dispatch_queue_create("Flickr fetcher", NULL);
dispatch_async(fetchQ, ^{
NSArray *photos = [FlickrFetcher recentGeoreferencedPhotos];
[document.managedObjectContext performBlock:^{
// perform in the NSMOC's safe thread (main thread)
for (NSDictionary *flickrInfo in photos) {
[Photo photoWithFlickrInfo:flickrInfo inManagedObjectContext:document.managedObjectContext];
// table will automatically update due to NSFetchedResultsController's observing of the NSMOC
}
// should probably saveToURL:forSaveOperation:(UIDocumentSaveForOverwriting)completionHandler: here!
// we could decide to rely on UIManagedDocument's autosaving, but explicit saving would be better
// because if we quit the app before autosave happens, then it'll come up blank next time we run
// this is what it would look like (ADDED AFTER LECTURE) ...
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:NULL];
// note that we don't do anything in the completion handler this time
}];
});
}
If someone is still facing the same issue using Objective-C, there is one more thing you need to do after getting API key: change all http:// to https:// within files in FlickrFetcher folder. This worked for me.

Display encrypted file using QuickLook framework or UiDocumentInteractionController

I have an encrypted word/excel/pdf file locally stored which I need to preview in my iPad app. I understand that QLPreviewController or UiDocumentInteractionController could be used to preview these files. I can very well use this
- (id <QLPreviewItem>) previewController: (QLPreviewController *) controller previewItemAtIndex: (NSInteger) index {
return [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:[documents objectAtIndex:index] ofType:nil]];
}
But the file is encrypted and when I decrypt it I would get hold of NSData object. How do I go about loading NSData in either of these.
Also I understand that I can very well store the NSData back as a local file and load it in Preview. But there is a constraint of not storing the unencrypted file locally.
If someone has already accomplished this and can help me out here it will be greatly appreciated.
Thanks
AJ
Since you are using Quick Look, your options are limited. You must give Quick Look an NSURL, which means it must be on the file system (or the Internet). Fortunately, this shouldn't be much of a problem. iOS devices use hardware-level encryption. When your file is encrypted, only your app has the key to decrypt it. So, your file will still be encrypted, but it will also be readable by your app and only your app.
Here's what you do:
Decrypt your file into an NSData object, which you've already done.
Write the file to a location that will not get uploaded to iCloud nor backed up by iTunes. The tmp directory is probably the best choice. The code looks something like this:
NSData * data = // Your decrypted file data.
NSString * fileName = // Whatever you want to name your file.
NSString * path = [NSTemporaryDirectory() stringByAppendingPathComponent:fileName];
NSURL * url = [NSURL URLWithString:path];
NSError * error = nil;
BOOL success = [data writeToURL:url
options:NSDataWritingFileProtectionComplete
error:&error];
if (success) {
// Give the URL to Quick Look.
}
else {
// An error happened. See the 'error' object for the details.
}
At this point you have an NSURL which you can use with Quick Look. Don't forget to delete the decrypted file when you are done with it.
There are a few things to note about on-disk encryption:
It is only supported on iOS 4.0+.
It may not work on "older" devices.
The user must have an active passcode.
If you use NSDataWritingFileProtectionComplete, the file is not accessible while the device is locked. If you need to access the file while the app is locked, then you should use NSDataWritingFileProtectionCompleteUnlessOpen or NSFileProtectionCompleteUntilFirstUserAuthentication instead. This will still give you great protection, even if the device is stolen and jailbroken. Be aware, though, that these encryption options are only available on iOS 5.0+
For more details for on-disk encryption, check out the iOS App Programming Guide
After doing some digging, I found out that QLPreviewController is using UIWebView underneath, and calls the loadRequest: to load the requested file.
Another way to accomplish what you desire is to make a private Category on UIWebView,
and use method swizzling to override the loadRequest: method, and call instead the loadData:MIMEType:textEncodingName:baseURL: method.
Beware that:
1) In low-memory scenarios (i.e. large files) a black screen with
"Error to load the document" appears, if that concerns you. (The
unhacked QLPreviewController knows how to handle these scenarios
very well and present the document).
2) I'm not sure Apple are going
to approve this kind of hack, although no private APIs are used
here.
code:
#implementation UIWebView (QLHack)
- (void)MyloadRequest:(NSURLRequest *)request
{
// Check somehow that it's the call of your QLPreviewController
// If not, just call the original method.
if (!insideQLPreviewController)
{
// Call original implementation
[self MyloadRequest:request];
}
else
{
// Load the real data you want
[self loadData:data MIMEType:mimeType textEncodingName:nil baseURL:someURL];
}
}
+ (void)load
{
method_exchangeImplementations(class_getInstanceMethod(self, #selector(loadRequest:)), class_getInstanceMethod(self, #selector(MyloadRequest:)));
}
#end
Actually, writing a file to a tmp directory is still insecure. The other alternative is to use UIWebView with NSURLProtocol and allow decrypting this data on the fly.
One way could be.
use Temp Dir , Save File in Temp , Make NSURL From that Temp File and Display and then Delete that temp Dir after that.
Thanks.

Load static google map into UIImageView?

I'm trying to show a small static google map in my app. I'm wondering if it's possible to do this using UIImageView? It doesn't seem to be working for me but maybe I'm doing something wrong.
This is what I have (I stripped the URL so that it's easier to read):
NSURL *mapurl = [[NSURL alloc] initWithString:#"http://maps.google.com/maps/api/staticmap?[...]"];
NSData *mapdata = [[NSData alloc] initWithContentsOfURL:mapurl];
UIImage *uimap = [[UIImage alloc] initWithData:mapdata];
self.map.image = uimap; // map is my UIImageView
[mapurl release];
[mapdata release];
[uimap release];
I know my UIImageView is setup correctly because if I replace the URL with one of an image then it loads fine. Also I know the google maps URL is correct because if I load it straight into a browser it shows up fine.
I'm starting to think that this might not be possible. If anyone has any ideas or alternatives please share.
Thanks.
Well I ended up finding a solution for this so I'll post it in case someone else runs into the same issue.
First I changed the way I load the image to using NSURLConnection. I don't think this particular change makes a difference but this is what allowed me to find the problem. When trying to load the URL I got a "bad url" error. So I did some searching on that and turns out there are some invalid characters in the google static map URL that must be escaped.
So basically just call this on the url and you should be good to go:
// The URL you want to load (snipped for readability)
NSString *mapurl = #"http://maps.google.com/maps/api/staticmap?[...]";
// Escape the string
mapurl = [mapurl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
I haven't tested this solution with the code I have in my original post but I did test it with my new NSURLConnection implementation and it works perfectly. I assume it'll work fine with the code above as well since it was just a matter of escaping the string.

Using tel: url to initiate a call doesn't return control

I have an app that worked just fine in version 2.2.1 of the iphone, but have ran into an issue when I upgraded my dev iphone to 3.1.2. Before, dialing a number worked fine, as when the call was ended, my application was loaded. Now, after I hit end call, it loads the default phone application. Does anybody know why this is? I've looked at the diff's from sdk 2.x to 3.x and can't find any reason why this would change. Thanks
This was indeed changed from 3.0 to 3.1. If you need the "prompt-for-call" and "relaunch-app-after-call" there are 2 work-arounds:
Option 1: Create a UIWebView and load your tel: URL.
// assuming you have an ivar to store a weak reference to a UIWebView:
// UIWebView *phoneCallWebView;
- (void) dialPhoneNumber:(NSString *)aPhoneNumber
{
NSURL *phoneURL = [NSURL URLWithString:[NSString stringWithFormat:#"tel:%#",aPhoneNumber]];
if ( !phoneCallWebView ) {
phoneCallWebView = [[UIWebView alloc] initWithFrame:CGRectZero];
}
[phoneCallWebView loadRequest:[NSURLRequest requestWithURL:phoneURL]];
}
- (void) dealloc
{
// cleanup
[phoneCallWebView release], phoneCallWebView = nil;
[super dealloc];
}
Option 2: Initiate your call with with the telprompt:<number> URL scheme instead of tel:<number>. Note that this is an undocumented API feature, but it's what UIWebView uses when you tap on a phone number link in a webview (or in MobileSafari). If you are targeting iPhone >= 3.0, there are not any problems using telprompt: (tel: and telprompt: are identical on 3.0). I'm not sure about iPhone OS 2.x.
In general, option 2 works and is easier, but option 1 is actually a "legal" workaround. Unfortunately, there does not seem to be a way to separate the "prompt-for-call" and "relaunch-after-call" behaviors. On iPhoneOS >= 3.1, you can either get both, or neither.
Yes, Apple changed this behavior from 3.0 to 3.1 (I believe, could also be from 2.x to 3.0). They have acknowledged that the change was deliberate and not a bug. There is no workaround that I know of. You just have to live with it a file an enhancement request if you think the old behavior should be made available again.
But both UIWebView and telepump will introduce a "pop up box" require user to confirm if user would like to dial the number. I am wondering if there are some solutions that could get rid of "pop up box" Thank you.
NSURL* url = [[NSURL alloc] initWithString:[NSString stringWithFormat:#"telprompt:%#",[SLUser sharedInstance].ivrNumber]];
[[UIApplication sharedApplication] openURL:url];

Using TwitPic API from ObjectiveC/iPhone

There's a similar question on here about this which I've read and I've tried to follow the advice given there... and I think I'm 95% complete but the remaining 5%... well you know ;-)
So I'm trying to call the twitPic API to upload an image and I've got the image contained in a UIImageView which I'm displaying on the screen (I can see it so it's definitely there). My code to form the API call looks like this:
NSURL *url = [NSURL URLWithString:#"http://twitpic.com/api/upload"];
NSString *username = #"myUsername";
NSString *password = #"myPassword";
NSData *twitpicImage = UIImagePNGRepresentation(imageView.image);
// Now, set up the post data:
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:twitpicImage forKey:#"media"];
[request setPostValue:username forKey:#"username"];
[request setPostValue:password forKey:#"password"];
// Initiate the WebService request
[request start];
I get an error back from it stating 'image not found'.
Is it obvious what I'm doing wrong? Any hints at all? I'm only a week deep in ObjectiveC so it's quite likely it's a real newbie error.
On the same track - it's not clear to me how I can capture a success or failure properly in code here - I'm currently dumping the 'request responseString' to an alert which isn't the best thing - how can I check the result properly?
I've also seen the use of 'NSLog' - which I suspect is a debugging/console logging tool - but I can't see the output from this anywhere in XCode - it doesn't SEEM to be shown in the debugger - any clues at all?!
Sorry if the above is really dumb - I can take a little ridicule - but I'm kind of isolated with my iPhone adventures - no one to bounce anything off etc - so I'm venting it all off here ;-)
Cheers,
Jamie.
You need to use the setData method to copy the image data into the post, like this:
[request setData:twitPicImage forKey:#"media"];
You're making a synchronous call, which is going to stall your app while you upload all that image data - you might want to switch to using an NSOperationQueue, or the ASINetworkQueue subclass that allows you to show a progress bar.
You should be able to see NSLog output in the debugger window of XCode. Make sure you've switched to this (control top left with a spray can on). You can also launch the console.