I use asihttprequest to download multiple files and I'm wondering how I can remove the associated UIProgressview with the right request when the download is done.
NSMutableArray *contentArray contains the ASIHTTPRequest and NSMutableArray *progArray contains my custom UIProgressview.
-(void)addDownload:(NSString *)theURL withName:(NSString *)fileName
{
theProgress = [[PDColoredProgressView alloc] initWithFrame:CGRectMake(3, 17, 314, 14)];
//...
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:theURL]];
//..
[request setDelegate:self];
[request setDownloadProgressDelegate:theProgress];
request.allowResumeForFileDownloads = YES;
[request startAsynchronous];
[request setShouldContinueWhenAppEntersBackground:YES];
[contentArray addObject:request];
[progArray addObject:theProgress];
[theProgress retain];
[self.tableView reloadData];
}
- (void)requestFinished:(ASIHTTPRequest *)request{
[contentArray removeObject:request];
[progArray removeObject:theProgress];
NSLog(#"%#",progArray);
NSLog(#"%#",contentArray);
[self reloadMyData];
[self.tableView reloadData];
}
The problem is that this code remove the last progressview even if the there are 3 downloads in contentArray and the second one finish first.
Can you help me with this ?
If you need to remove progress view that's associated with finished request you can get it from request's downloadProgressDelegate property:
- (void)requestFinished:(ASIHTTPRequest *)request{
PDColoredProgressView *progress = (PDColoredProgressView*)request.downloadProgressDelegate;
[contentArray removeObject:request];
if (progress)
[progArray removeObject:progress];
[self reloadMyData];
[self.tableView reloadData];
}
Related
i am trying to load a url in uiwebview in xcode and it is loading just fine but problem is that there is ZERO user interaction with it. i can not touch any button on it or can not even scroll it. i have already tried Allow Arbitrary Loads = YES in info.plist but nothing happened here is my code.
[webPage setDelegate:self];
[webPage loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://url.com"]]];
[webPage addSubview:activityIndicatorView];
here is more code from .h:
#interface ViewController : UIViewController<UIWebViewDelegate>{
IBOutlet UIWebView *webPage;
}
#property (retain, nonatomic) IBOutlet UIWebView *webPage;
its s simple uiwbview from interface builder in a simple uiviewcontroller.
and here is my info.plist
I figure out that problem might be here in this part of the code. there is a menu in my uinavigationbar as well which is loading xml menu. wait i will post my code.
- (void) makeMenu{
#try {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{
NSURL *url=[NSURL URLWithString:#"http://url/xml-menu.php"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
[request setHTTPMethod:#"POST"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
NSError *error = nil;
NSHTTPURLResponse *response = nil;
NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
if ([response statusCode] >=200 && [response statusCode] <300)
{
rssOutputData = [[NSMutableArray alloc]init];
xmlParserObject =[[NSXMLParser alloc]initWithData:urlData];
[xmlParserObject setDelegate:self];
[xmlParserObject parse];
}
dispatch_async(dispatch_get_main_queue(), ^{
sideMenu.delegate = self;
NSInteger count;
NSMutableArray *itemsArry = [[NSMutableArray alloc] init];
count = [rssOutputData count];
for (int i = 0; i < count; i++){
BTSimpleMenuItem *item = [[BTSimpleMenuItem alloc]initWithTitle:[[rssOutputData objectAtIndex:i]xmltitle] image:[UIImage imageNamed:#"arrow.png"]
onCompletion:^(BOOL success, BTSimpleMenuItem *item) {
[webPage loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[[rssOutputData objectAtIndex:i]xmllink]]]];
}];
[itemsArry addObject:item];
}
NSArray *itemSarry=[[NSArray alloc] initWithArray:itemsArry];
sideMenu = [[BTSimpleSideMenu alloc]initWithItem:itemSarry addToViewController:self];
});
});
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
}
when i call this method in viewdidload uiwebview stop responding. And if i do not call this part uiwebview works just fine. please help me i need this menu as well.
Try this:
webPage.userInteractionEnabled = YES;
i am creating 2 buttons one for like and one for dislike when i click like button its disable and also disable dislike button same time.and so on. and its not change when i am run the application second time. i am implemented for that its work but problem is that when i run my application second time once again that button enable. problem is that i don't want that button same button enable.please help me what is the problem in my code
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationController.navigationBar.barTintColor = [UIColor colorWithRed:102/255.0
green:102/255.0 blue:204/255.0 alpha:1.0];
self.navigationController.navigationBar.titleTextAttributes =
#{NSForegroundColorAttributeName : [UIColor whiteColor]};
smsdisplaytext.editable=NO;
smsdisplaytext.backgroundColor= [UIColor colorWithRed:102/255.0 green:102/255.0
blue:204/255.0 alpha:1.0];
self.navigationItem.title=#"Insta SMS";
[ self getSmsData];
[self smsdisplay];
[self getLike];
}
-(void)sendlike
{
NSURL *url = [NSURL URLWithString:
#"http://sms.instatalkcommunications.com/apireq/AddRatingForSMS"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[NSString stringWithFormat:#"%d",1] forKey:#"t"];
[request setPostValue:#"admin" forKey:#"h"];
[request setPostValue:[NSString stringWithFormat:#"%#",self.Id] forKey:#"cid"];
[request setPostValue:[NSString stringWithFormat:#"%d",1234567890] forKey:#"token"];
[request setPostValue:#"test#test.com" forKey:#"email"];
[request setTag:2];
[request setPostValue:#"true" forKey:#"like"];
[request setDelegate:self];
[request startAsynchronous];
}
-(void)senddislike
{
NSURL *url = [NSURL URLWithString:
#"http://sms.instatalkcommunications.com/apireq/AddRatingForSMS"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[NSString stringWithFormat:#"%d",1] forKey:#"t"];
[request s etPostValue:#"admin" forKey:#"h"];
[request setPostValue:[NSString stringWithFormat:#"%#",self.Id] forKey:#"cid"];
[request setPostValue:[NSString stringWithFormat:#"%d",1234567890] forKey:#"token"];
[request setPostValue:#"test#test.com" forKey:#"email"];
[request setPostValue:#"false" forKey:#"Like"];
[request setTag:3];
[request setDelegate:self];
[request startAsynchronous];
}
- (void) requestFinished:(ASIHTTPRequest *)request
{
NSString *responseString = [request responseString];
responseString = [request responseString];
NSLog(#"%#",responseString);
if(request.tag==1)
{
SBJsonParser *parser = [[SBJsonParser alloc] init] ;
NSArray *jsondata = [parser objectWithString:responseString];
NSLog(#"%#",jsondata);
for (NSObject* item in jsondata)
{
likelabel.text = [[item valueForKey:#"Liked"] stringValue];
dislikelabel.text = [[item valueForKey:#"Disliked"] stringValue];
}
}
else if(request.tag==2)
{
[self getLike];
}
/////// getting comment
else if(request.tag==4)
{
// get comments
SBJsonParser *parser = [[SBJsonParser alloc] init] ;
NSMutableArray *jsondata = [parser objectWithString:responseString];
for(int i=0;i<jsondata.count;i++)
{
NSObject *temp = [jsondata objectAtIndex:i];
NSMutableDictionary *message = [[NSMutableDictionary alloc] init];
message[kMessageContent]=[temp valueForKey:#"Comment"];
message[#"Timestamp"]=[self dateWithJSONString:[temp valueForKey:#"CreatedDate"]];
last=[[temp valueForKey:#"Id"] integerValue];
[_chatController addNewMessage:message];
}
}
else
{
////post comment
[self getComment];
}
}
//this method for getting like and dislike
-(void)getLike
{
NSString *url = [NSString
stringWithFormat:#"http://sms.instatalkcommunications.com/apireq/GetRatingsForSMS?
t=1&h=admin&cid=%#&token=1234567890&email=test#test.com",self.Id];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setRequestMethod:#"GET"];
[request setTag:1];
[request setDelegate:self];
[request startAsynchronous];
}
// here for like button
- (IBAction)btnlike:(id)sender
{
NSLog(#"keypress");
[self sendlike];
[self getLike];
UIButton *btnlike = (UIButton *) sender;
btnlike.enabled = NO;
UIButton *btndislike = (UIButton *) sender;
btndislike.enabled = NO;
}
//here i am action for dislike button
- (IBAction)btndislike:(id)sender
{
NSLog(#"keypress");
[self senddislike];
[self getLike];
UIButton *btndislike = (UIButton *) sender;
btndislike.enabled = NO;
_btnlike.enabled = NO;
}
#end
As I'm not an native english speaker, I hope I've understood correctly what you are trying to achieve.
If I understand correctly, You have a 'Like' and 'Dislike' buttons, and when the user presses on one of them, you want both to be disabled,
Which is working correctly for the current run.
But, if I understand correctly, the next time the app runs, the buttons are 'reset' to be enabled, and you don't want that,
You want the button be disabled every time the app runs.
If I did understood you correctly, the way to 'save' state of objects is using the NSUserDefaults.
You might have a better way to implement it than my example below, but it should do the trick, and also give you a better understanding on how to implement it, incase you need to modify my code.
Add the following method:
-(void)disableButtons {
[[NSUserDefaults standardUserDefaults] setBool: YES forKey: #"buttonsDisabled"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
now, at the end of the 'Like' and 'Dislike' buttons, just call the following methods by adding to your code:
[self disableButtons]
Now, add the following to viewDidLoad:
// someplace in viewDidLoad
BOOL bottunsDisabled = [[NSUserDefaults standardUserDefaults] boolForKey: #"buttonsDisabled"];
if(buttonsDisabled) {
self.btndislike.enabled = NO;
self.btnlike.enabled = NO;
}
The buttons defaults state are enabled, so the above code will change them, incase they have been disabled in previous runs.
Note that I also assumed you have a reference to the buttons (I assume you've created them in interface builder), if not, just create a property/ivar that will hold a reference to them.
And as Ian MacDonald mentioned above, in the 'Like' button method, you are disabling only the 'Like' button twice, and not disabling the 'Dislike' button.
In order to fix it, change the code to the following (again, I assume you have some sort of reference to both of them):
- (IBAction)btnlike:(id)sender
{
NSLog(#"keypress");
[self sendlike];
[self getLike];
self.btnlike.enabled = NO;
self.btndislike.enabled = NO;
[self disableButtons];
}
As I've said above, I'm not an native english speaker,
So I hope my answer was clear enough.
If something isn't clear, just tell me and I'll try to rephrase it.
Good luck mate!
update
I think the problem is with the networkQueue. When I replace [self.networkQueue addOperation:request] with [request startAsynchronous] or [request startSynchronous], it works.
I update the code to make it more clear.
original
I use ASIHTTPRequest to upload a file of json with encoded image (or [request setFile:imagefile...]), but I cannot update the progress.
I got only one output: value: 1.000000, which means the uploads finished.
incrementUploadSizeBy was never triggered.
I have searched online a lot but still cannot find a answer. Here is my code.
+ (ASIEngine *)sharedInstance {
static ASIEngine *sharedInstance = nil;
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (id)init {
if (self = [super init]) {
_networkQueue = [ASINetworkQueue queue];
[_networkQueue setMaxConcurrentOperationCount:MAX_CONCURRENT_OPERATION_COUNT];
[_networkQueue setDelegate:self];
[_networkQueue go];
}
return self;
}
- (void)upload:(NSString *)imageJsonString onCompletion:(void(^)(NSString *responseString))onCompletion onFailed:(void(^)(NSError *error))onFailed {
__unsafe_unretained __block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:UPLOAD_URL]];
[request setShowAccurateProgress:YES];
[request setUploadProgressDelegate:self];
[request setPostValue:imageJsonString forKey:#"imageString"];
[request setCompletionBlock:^{
NSString *responseString = [request responseString];
onCompletion(responseString);
}];
[request setFailedBlock:^{
onFailed([request error]);
}];
[self.networkQueue addOperation:request];
}
#pragma mark - ASIProgressDelegate
- (void)setProgress:(float)newProgress {
NSLog(#"value: %f", newProgress);
}
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength {
NSLog(#"data length: %lld", newLength);
}
If you are uploading a string, you probably have so little data to upload (as opposed to when uploading a picture), that it uploads everything in one step. You could try reading a huge string from a file and see what happens.
I'm loading JSON data using ASIHTTPRequest. I'm requesting huge amount of data when the user touch the button (Here I'm loading another view which will request JSON data). It takes about 15 sec. to load. How can I use the UIActivityIndicatiorView once the user touch the button until the data loads.
Anyone did this before or any suggestion to improve user performance?
-(void) startRequest:(NSString*)username password:(NSString*)password
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:mainUrl];
[request setDelegate:self];
[request setDidFailSelector:#selector(requestFailed:)];
[request startAsynchronous];
[self.addSubview:self.indicator];
[indicator startAnimating];
}
-(void) requestFinished: (ASIHTTPRequest *) request {
[self.indicator stopAnimating];
[self.indicator removeFromSuperview];
}
Here is a sample for using the ASIHTTPRequest and UIActivityIndicator
-(void) loadImageFromURL:(NSURL *) url withActivityIndicator:(BOOL) yesOrNo {
__block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
UIActivityIndicatorView *activityIndicator = nil;
if (yesOrNo == YES) {
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
[activityIndicator setCenter: self.center];
[activityIndicator startAnimating];
[self addSubview: activityIndicator];
}
[request setCompletionBlock: ^{
self.image = [UIImage imageWithData: [request responseData]];
[activityIndicator removeFromSuperview];
[activityIndicator release];
}];
[request setFailedBlock: ^{
[activityIndicator removeFromSuperview];
[activityIndicator release];
}];
[request startAsynchronous];
}
#end
Here i am trying to call my ASIHTTPRequest in a GCD. Sometimes the comletion blocks and failed blocks are not executing. What i want to do is, after this request finished, i have to use the returned data in a another ASIHTTPRequest. So how to improve this code:
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:url]];
[request setCompletionBlock:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSData *_responseData = [request responseData];
NSString *response = [[NSString alloc] initWithData:_responseData encoding:NSASCIIStringEncoding] ;
self.albumDic = [response JSONValue];
[response release];
dispatch_async(dispatch_get_main_queue(), ^{
[self GetDictionary:self.albumDic];
});
});
}];
[request setFailedBlock:^{
NSError *error = [request error];
NSLog(#"Error : %#", error.localizedDescription);
}];
[request startSynchronous];
Don't go that way. You're doing threading on threading (GCD uses threading and so does ASIHTTPRequest when used asynchronously).
Use ASINetworkQueue instead - read about it here
Here is a simple way you could use it:
- (void)addRequestsToNetworkQueue:(NSArray *)requests {
// Stop anything already in the queue before removing it
[[self networkQueue] cancelAllOperations];
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self networkQueue] setDelegate:self];
[[self networkQueue] setRequestDidFinishSelector:#selector(requestFinished:)];
[[self networkQueue] setRequestDidFailSelector:#selector(requestFailed:)];
[[self networkQueue] setQueueDidFinishSelector:#selector(queueFinished:)];
//Add all requests to queue
for (ASIHTTPRequest *req in requests) {
[[self networkQueue] addOperation:req];
}
//Start queue
[[self networkQueue] go];
}
ASINetworkQueue provides many delegate methods (most are also customizable), so you can update the GUI when a request is finished and so forth. It is asynchronous, so GCD is unnecessary.