I've written code that gathers images from JSON requests and attempts to add them to an NSMutableArray to be used later in a table view. The problem is after adding the image objects to the array, the size of my NSMutableArray is 0. Here is the relevant code:
#implementation example{
NSMutableArray *_placeImages;
}
-(void)viewDidLoad{
...
_placeImages = [[NSMutableArray alloc] init];
}
-(void)JsonQuery {
...
// Retrieve the results of the URL.
dispatch_async(kMyQueue, ^{
[self downloadImages];
[self performSelectorOnMainThread:#selector(reloadTableData) withObject:NULL waitUntilDone:YES];
});
}
-(void)downloadImages{
...
NSData* data = [NSData dataWithContentsOfURL: url];
UIImage* image = [UIImage imageWithData:data];
[_placeImages addObject:image];
}
you must alloc NSMutableArray first:
_placeImages = [[NSMutableArray alloc] init];
or you can using lazy init:
- (NSMutableArray *)placeImages
{
if (!_placeImages) {
_placeImages = [[NSMutableArray alloc] init];
}
return _placeImages
}
Related
How can I use activity indicator in second view controller to let data to be complete load
first VC
- (IBAction)btnOpenHTML:(id)sender {
RecievVC *obj = [self.storyboard instantiateViewControllerWithIdentifier:#"RecievVC"];
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:lblName.text forKey:#"lblname"];
//........Lots of Data........(then in the end of 1st VC)........//
obj.dicData = dict;
[self.navigationController pushViewController:obj animated:true];
}
#end
the 2nd VC Code after viewdidload
- (void)viewDidLoad {
[super viewDidLoad];
[self->webView.scrollView setScrollEnabled:true];
[self->webView loadHTMLString:[self getHTMLStirng] baseURL:[NSURL URLWithString:#""]];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
-(NSString *)getHTMLStirng {
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"resumeT" ofType:#"html"];
NSString *strHTML = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
if (self.dicData) {
strHTML = [strHTML stringByReplacingOccurrencesOfString:#"#NAME" withString:[_dicData valueForKey:#"lblname"]];
//...............Lots of Data......Then at the end of 2nd VC............//
}return strHTML;
}
what I main by lots of data, it's around 150 of keys and value have to be send from 1st VC to 2nd VC.
any idea?
You could try GCD:
// instantiate the activity indicator
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleGray];
activity.center = self.view.center;
// start your activity indicator
[activity startAnimating]
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// load data on background thread
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:lblName.text forKey:#"lblname"];
//........Lots of Data........(then in the end of 1st VC)........//
// update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^{
// stop your activity indicator
[activity stopAnimating]
RecievVC *obj = [self.storyboard instantiateViewControllerWithIdentifier:#"RecievVC"];
obj.dicData = dict;
[self.navigationController pushViewController:obj animated:true];
});
});
I have a property that I am initializing in viewDidLoad, that is declared in my header file. In viewDidLoad I declare it here:
- (void)viewDidLoad {
[super viewDidLoad];
viewControllerList = [NSMutableArray new];
vc = [self.storyboard instantiateViewControllerWithIdentifier:#"moreSpeedyCafeViewController"];
[self loadDefaults];
self.dataSource = self;
In the loadDefaults method, I am iterating through an array and setting its properties. As I step through in the debugger, the values are nil even after being set. The values in the dictionary are not nil, I have checked that. I'm not sure why this is happening.
for (NSMutableDictionary *newDict in array) {
tempDict = newDict;
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:[[tempDict objectForKey:#"ImageUrls"]objectAtIndex:0]]];
vc.dmsImageView.image = [UIImage imageWithData:imageData];
vc.dmsDescriptionLabel.text = [tempDict objectForKey:#"Title"];
vc.dmsLinkText.text = [tempDict objectForKey:#"LinkText"];
vc.index = [array indexOfObject:tempDict];
[viewControllerList addObject:vc];
}
I'm trying to make a module for react-native using NYTPhotoViewer and asynchronous image downloading. It works, but first image never stops to animate loading when the other downloads and shows. Interesting, that if I swipe some images (2 and more), the first image will render. The code is here:
#import <NYTPhotoViewer/NYTPhotosViewController.h>
#import "NYTImageViewer.h"
#import "NYTExamplePhoto.h"
#interface NYTImageViewer () <NYTPhotosViewControllerDelegate>
#property (nonatomic) NSArray *photos;
#end
#implementation NYTImageViewer
RCT_EXPORT_MODULE()
RCT_EXPORT_METHOD(open:(NSArray *)urls)
{
dispatch_async(dispatch_get_main_queue(), ^{
NSArray *photos = addPhotos(urls);
NYTPhotosViewController *photosViewController = [[NYTPhotosViewController alloc] initWithPhotos:photos];
UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
[ctrl presentViewController:photosViewController animated:TRUE completion: nil];
});
}
NSArray* addPhotos(NSArray *urls) {
NSMutableArray *photos = [NSMutableArray array];
for (int i = 0; i < [urls count]; i++) {
NYTExamplePhoto *photo = [[NYTExamplePhoto alloc] init];
dispatch_async(dispatch_get_global_queue(0,0), ^{
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: urls[i]]];
if ( imageData == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
photo.image = [UIImage imageWithData: imageData];
});
});
[photos addObject:photo];
}
return photos;
}
#end
How can I fix it?
You shouldn't/can't load that way from a remote URL, and with the dispatch_async it's generating the expected behavior:
NSData * _data = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: urls[i]]];
You must use NSURLSession or NSURLConnection via asynchronous method for remote calls, and you'll have to handle recursion at the callback.
I need to load a image from a URL into a UIImageView. Each time the URL would be different because i am JSON parsing a website. I am able to get the URL. However when i run the app, there is no image in the UIImageView.
This is my code
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
if ([eventNameDesc containsString:#"src="]) {
eventNameDesc = #"";
}
else {
eventDescription.text = eventNameDesc;
}
self.navigationItem.rightBarButtonItem=[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:#selector(shareButtonPressed)];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(IBAction)shareButtonPressed {
NSString *shareText = eventNameDesc;
NSArray *itemsToShare = #[shareText];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
activityVC.excludedActivityTypes = #[];
[self presentViewController:activityVC animated:YES completion:nil];
}
- (void)loadImage {
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:self.imageURL]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
- (void)displayImage:(UIImage *)image {
[self.ImageView setImage:image]; //UIImageView
}
#end
What is wrong with my code? Somebody please help.
You can make a UIImage object using the code provided here
After that you can add your UIImage object to any UIImageView object.
This is the code that works for me.
UIImage *anImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://4.bp.blogspot.com/-K7vl-ShXrNc/VQU-D0NTFgI/AAAAAAAAAOg/aBIUOwF2nEQ/s1600/contact.png"]]];
UIImageView *temp = [[UIImageView alloc] initWithImage:anImage];
[self.view addSubview:temp];
Here is a screenshot.
I want to load some "image" (In remote server) in a UIScrollView with NSOperatoinQueue. Because If I load it with normal NSURL, NSData or with NSMutableURLRequest it takes too much time to load for all the images. After that I show those images in UIButton. Here is my code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self startAnimation:nil];
self.imageDownloadingQueue = [[NSOperationQueue alloc] init];
self.imageDownloadingQueue.maxConcurrentOperationCount = 4; // many servers limit how many concurrent requests they'll accept from a device, so make sure to set this accordingly
self.imageCache = [[NSCache alloc] init];
[self performSelector:#selector(loadData) withObject:nil afterDelay:0.5];
}
-(void) loadData
{
adParser = [[AdParser alloc] loadXMLByURL:getXMLURL];
adsListArray = [adParser ads];
displayArray = [[NSMutableArray alloc] init];
for (AdInfo *adInfo1 in adsListArray)
{
AdInfo *adInfo2 = [[AdInfo alloc] init];
[adInfo2 setBannerIconURL:adInfo1.bannerIconURL];
[adInfo2 setBannerIconLink:adInfo1.bannerIconLink];
[displayArray addObject:adInfo2];
}
[self loadScrollView];
[activityIndicator stopAnimating];
}
-(void) loadScrollView
{
[self.scrollView setScrollEnabled:YES];
[self.scrollView setContentSize:CGSizeMake([displayArray count] * ScrollerWidth, ScrollerHight)];
for (int i = 0; i < [displayArray count]; i++)
{
adButtonOutLet = [[UIButton alloc] initWithFrame:CGRectMake(i*320, 0, ButtonWidth, ButtonHight)];
currentAd = [displayArray objectAtIndex:i];
NSString *imageUrlString = [currentAd bannerIconURL];
UIImage *cachedImage = [self.imageCache objectForKey:imageUrlString];
if (cachedImage)
{
[adButtonOutLet setImage:cachedImage forState:UIControlStateNormal];
}
else
{
[self.imageDownloadingQueue addOperationWithBlock:^
{
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageUrlString]];
UIImage *image = nil;
image = [UIImage imageWithData:imageData];
// add the image to your cache
[self.imageCache setObject:image forKey:imageUrlString];
// finally, update the user interface in the main queue
[[NSOperationQueue mainQueue] addOperationWithBlock:^
{
[adButtonOutLet setImage:image forState:UIControlStateNormal];
}];
}];
}
adButtonOutLet.userInteractionEnabled= YES;
[adButtonOutLet setTag:i];
[adButtonOutLet addTarget:self action:#selector(goToURL:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:adButtonOutLet];
}
}
Can anyone tell me what's wrong with the above code? There is no problem of parsing or retrieving data from Remote server. I check it by NSLog. I think the NSOperationQueue have some problem, which I can't manage properly. Thanks in advance. If you needed more information, I will attach here.
Have a nice day.
Not sure if this is your problem or your solution, its hard to tell without testing myself.
Taken from RayWenderlich
addOperationWithBlock: if you have a simple operation that does not
need to be subclassed, you can create an operation using the block
API. If you want to reference any object from outside in the block,
remember that you should pass in a weak reference. Also, if you want
to do something that is related to the UI in the block, you must do it
on the main thread:
// Create a weak reference
__weak MyViewController *weakSelf = self;
// Add an operation as a block to a queue
[myQueue addOperationWithBlock: ^ {
NSURL *aURL = [NSURL URLWithString:#"http://www.somewhere.com/image.png"];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];
UIImage *image = nil;
If (data)
image = [UIImage imageWithData:data];
// Update UI on the main thread.
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
weakSelf.imageView.image = image;
}];
}];