i am newBie in iOS Development.i make a Segmented Control For my Application and I want to Parsed Different WebService Data For Each Scrollview Contain For that i Use HMSegmented Controll and Set A scrollview For it like as
Here my Main view Controller Contain Code liken as
ViewController *latest=[[ViewController alloc]initWithNibName:#"ViewController" bundle:nil];
[latest.view setFrame:CGRectMake(0, 0, self.view.frame.size.width,self.view.frame.size.height)];
latest.index=0;
[self addChildViewController:latest];
[self.scrollView addSubview:latest.view];
ViewController *latest2=[[ViewController alloc]initWithNibName:#"NavuViewController" bundle:nil];
[latest2.view setFrame:CGRectMake(320, 0, self.view.frame.size.width, self.view.frame.size.height)];
latest2.index=1;
[self addChildViewController:latest2];
[self.scrollView addSubview:latest2.view];
ViewController * latest3 =[[ViewController alloc]initWithNibName:#"NavuViewController" bundle:nil];
[latest3.view setFrame:CGRectMake(640, 0, self.view.frame.size.width, self.view.frame.size.height)];
latest3.index=2;
[self addChildViewController: latest3];
[self.scrollView addSubview: latest3.view];
Then it Contain Different View As i want
And in my View Controller.h file i Define index as int Variable
#property (assign) int index;
And Now I want to Fetch Data From Different Webservice Based on Index for that i Write a code in my ViewController.m file ViewDidLoad method i write a Code like as
-(void)view
{
[super viewWillAppear:animated];
[self.navuTable deselectRowAtIndexPath:self.navuTable.indexPathForSelectedRow animated:YES];
NSURL *url;
switch (self.index)
{
case 0:
url=[NSURL URLWithString:[NSString stringWithFormat:#"http://www.janvajevu.com/webservice/latest_post.php?page=%d",pageNum]];
break;
case 1:
{
NSString *urlString = #"http://www.janvajevu.com/webservice/categorylist.php?category=%E0%AA%9C%E0%AA%BE%E0%AA%A3%E0%AA%B5%E0%AA%BE%20%E0%AA%9C%E0%AB%87%E0%AA%B5%E0%AB%81%E0%AA%82&page=";
url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%d",urlString,pageNum]];
}
break;
case 2:
{
NSString *urlString = #"http://www.janvajevu.com/webservice/categorylist.php?category=%E0%AA%9F%E0%AB%87%E0%AA%B2%E0%AB%87%E0%AA%A8%E0%AB%8D%E0%AA%9F&page=";
url= [NSURL URLWithString:[NSString stringWithFormat:#"%#%d",urlString,pageNum]];
}
break;
default:
break;
}
dispatch_async(kBgQueue, ^{
data = [NSData dataWithContentsOfURL: url];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
-(void)fetchedData:(NSData *)responsedata
{
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.frame = CGRectMake(0, 0, 320, 44);
self.navuTable.tableFooterView = spinner;
if (responsedata.length > 0)
{
NSError* error;
self.json= [NSJSONSerialization JSONObjectWithData:responsedata options:kNilOptions error:&error];
if ([[_json objectForKey:#"data"] isKindOfClass:[NSArray class]])
{
NSArray *arr = (NSArray *)[_json objectForKey:#"data"];
[self.navuArray addObjectsFromArray:arr];
[self.navuTable reloadData];
[spinner startAnimating];
NSLog(#"Array %#",self.navuArray);
}
}
Then it is Load Same Data for All Index means Only Fetch Data From First Index Url It is Mot Load Data For Different Index for Different Segmented Control please Give me Solution For it.
thanks in advance.
Index stay at value of 0 all the time, it's not the first item , but it's the default value when you initialize it .
try to add the delegate of the Segment , see documentation and implement the ValueChanged: Delegate in which you can get the value of the selected index by yourSegment.selectedIndex ,, and that will be the value you should use to fetch different URLs.
otherwise the structure of your code is so week , you should use storyboard instead of nibs , maybe make a Model class with clean code then connect to your UI code . (MVC pattern)
hope that helps , post further data if you want more help . Good luck
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 want to put a UILabel and UIActivityIndicatorView into UITableView Footer i want when new Data Fetch then UIActivityIndicatorView Start animating and When Not any New Data Avaliable then Lable is Shown Into Table View Footer.
I Write Code for that but it is not Working
-(void)fetchedData:(NSData *)responsedata
{
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spinner.frame = CGRectMake(0, 0, 320, 44);
self.newsTable.tableFooterView = spinner;
UILabel *footerlabel=[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 320, 44)];
footerlabel.text=#"No New Data Avaliable";
footerlabel.backgroundColor=[UIColor whiteColor];
footerlabel.textColor=[UIColor redColor];
self.newsTable.tableFooterView =footerlabel;
if (responsedata.length > 0)
{
spinner.hidden=FALSE;
footerlabel.hidden=TRUE;
NSError* error;
self.json = [NSJSONSerialization JSONObjectWithData:responsedata options:kNilOptions error:&error];
if ([[_json objectForKey:#"data"] isKindOfClass:[NSArray class]])
{
NSArray *arr = (NSArray *)[_json objectForKey:#"data"];
[self.imageArray addObjectsFromArray:arr];
[self.newsTable reloadData];
NSLog(#"images,%#",self.imageArray);
[spinner startAnimating];
}
self.newsTable.hidden=FALSE;
}
if (responsedata.length == 0)
{
[spinner stopAnimating];
spinner.hidesWhenStopped=YES;
footerlabel.hidden=FALSE;
}
}
When I add a single View like as Lable/Spinner then it is working but when i add both at same then not any Controller is working.
Please Give me Solution.If It was Possible.
I'm using a collection view and trying to transition from loading the data synchronously to loading it asynchronously.
I know that the following currently works (it takes a while to load, but all the cells appear correctly when it's done):
// load projectData in main thread
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelectorOnMainThread:#selector(fetchProjects:)withObject:projectData waitUntilDone:YES];
I rewrote it to do everything asynchronously:
// load project data asynchronously
dispatch_async(bgQueue, ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
[self performSelector:#selector(fetchProjects:) withObject:projectData];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
When I run the app after loading the data asynchronously, the view appears empty (the cells have no content), but when I scroll, some of the cells begin to appear.
Is there anything else I need to call besides reloadData to get my collection cells to appear properly?
Here is my fetchProjects:
// get JSON data of projects
- (void)fetchProjects:(NSData *)responseData {
NSError * error;
NSDictionary * json = [NSJSONSerialization
JSONObjectWithData:responseData
options:kNilOptions
error:&error]; // get dictionary from json data
NSDictionary * data = [json objectForKey:#"data"]; // get data in array
NSArray * projects = [data objectForKey:#"projects"];
NSDictionary * mostRecentProject = [projects objectAtIndex:0];
mostRecentProjectID = [mostRecentProject objectForKey:#"id"];
for (NSDictionary *currentProject in projects)
{
[projectIDs addObject: [currentProject objectForKey:#"id"]];
NSString *projectTitle = [currentProject objectForKey:#"title"];
NSString *trimmedProjectTitle = [projectTitle stringByTrimmingCharactersInSet:
[NSCharacterSet whitespaceAndNewlineCharacterSet]];
id delegate = [[UIApplication sharedApplication] delegate];
self.managedObjectContext = [delegate managedObjectContext];
Project *newProject = (Project *) [NSEntityDescription insertNewObjectForEntityForName:#"Project" inManagedObjectContext:[self managedObjectContext]];
CustomLabel *cellLabel=[[CustomLabel alloc]init];
cellLabel.text = trimmedProjectTitle;
NSLog(#"fetchprojects:%#",projectTitle);
[titles addObject:projectTitle];
CGSize maxLabelSize = CGSizeMake(screenWidth/2 - 30,100);
CustomLabel *titleLabel = [[CustomLabel alloc]init];
[titleLabel setNumberOfLines:0];
titleLabel.text = projectTitle;
CGSize expectedLabelSize = [titleLabel.text sizeWithFont:titleLabel.font constrainedToSize:maxLabelSize lineBreakMode:NSLineBreakByWordWrapping];
CGRect labelFrame = (CGRectMake(0, 0, screenWidth/2 - 30, 0));
labelFrame.origin.x = 0;
labelFrame.origin.y = screenWidth/2 - 70 - expectedLabelSize.height;
labelFrame.size.height = expectedLabelSize.height;
titleLabel.frame = labelFrame;
titleLabel.backgroundColor = [[UIColor blackColor]colorWithAlphaComponent:0.5f];
titleLabel.textColor =[UIColor whiteColor];
[titleLabel setFont: [UIFont fontWithName: #"HelveticaNeue" size:12]];
//NSLog(#"%#", titleLabel.text);
UIImageView *imagePreview = [[UIImageView alloc] initWithFrame:CGRectMake(7.5, 10, screenWidth/2 -30, screenWidth/2 -70)];
imagePreview.contentMode= UIViewContentModeScaleAspectFill;
imagePreview.clipsToBounds = YES;
[imagePreview setImage:[UIImage imageNamed:#"blank.png"]];
[imagePreview addSubview:titleLabel];
[imagePreview.subviews[0] setClipsToBounds:YES];
[projectContainers addObject: imagePreview];
}
}
You're doing a lot of UI work on a background thread which you really shouldn't do. From what I can see, the only line that really needs to be run on a background thread is this one:
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
The rest looks like it deals with setting up and displaying your UI and some CoreData stuff; all of that needs to be run on the main thread. The easiest way to do that and keep everything running in the right order would be something like this:
// NOTE: If you're sure you're already on the main thread here, you don't need the dispatch, but it's not going to hurt to leave it in.
dispatch_async(dispatch_get_main_queue(), ^{
UIView *loadingAnimation = loadingCircle;
loadingAnimation.tag = 15;
[self.collectionView addSubview:loadingAnimation];
[loadingCircle startAnimating];
});
dispatch_async(bgQueue, ^{
NSData * projectData = [NSData dataWithContentsOfURL:userUrl];
dispatch_async(dispatch_get_main_queue(), ^{
[self fetchProjects:projectData];
NSLog(#"finished with loading projects");
UIView *viewToRemove = [self.view viewWithTag:15];
[viewToRemove removeFromSuperview];
[self.collectionView reloadData];
});
});
Note: I also changed [self performSelector:#selector(fetchProjects:) withObject:projectData] to [self fetchProjects:projectData]; you don't really need to go through performSelector: there.
I'm a noobie in the Objective-C language, and I have a little problem.
In fact, I have 2 TableViews, and when I go from one to the other I parse some XML from the internet. The parsing is doing well, but I wanted to add an UIActivityIndicatorView between those 2 views to tell to the user that something is loading.
So, to do that, I wanted to do the parsing in another thread and show the UIActivityIndicatorView in the main thread. So here's my code :
- (void)viewDidLoad
{
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator;
activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activityIndicator.center = self.view.center;
[self.view addSubview: activityIndicator];
activityIndicator.startAnimating;
dispatch_queue_t queue = dispatch_get_global_queue(0,0);
dispatch_async(queue, ^{
NSError *error = nil;
// we will put parsed data in an a array
titles = [[NSMutableArray alloc] init];
urls = [[NSMutableArray alloc] init];
CXMLDocument *rssParser = [[CXMLDocument alloc] initWithContentsOfURL:[NSURL URLWithString:_emissionSelectionnee] options:0 error:&error];
NSArray *nodes = NULL;
nodes = [rssParser nodesForXPath:#"//rss/channel/item/title" error:nil];
for (CXMLElement *title in nodes) {
[titles addObject:[title stringValue]];
}
nodes = NULL;
nodes = [rssParser nodesForXPath:#"//rss/channel/item/enclosure" error:nil];
for (CXMLElement *url in nodes) {
[urls addObject:[[url attributeForName:#"url"] stringValue]];
}
dispatch_sync(dispatch_get_main_queue(), ^{
activityIndicator.stopAnimating;
});
}
}
So now, the UIActivityIndicator shows up, but the cells are empty.. When I do not use the dispatch_queue_t, it works well..
Does someone have an idea?
Thank you in advance!
You need to reload your Table view (in the same block where you hide the activity indicator):
[self.tableView reloadData]
UPDATE #1: forgot to mention this is running on an iPad app
This is my revised code (still not working, but got rid of the unnecessary code):
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"custImage"] URLByAppendingPathExtension:#"png"];
NSError*writeError = nil;
[client.aClientImage writeToURL:fileURL options:0 error:&writeError];
NSAssert(writeError==nil, writeError);
// write appointment info
NSString *htmlString;
if(client.aClientEMail.length > 0) {
htmlString = [NSString stringWithFormat:NSLocalizedString(#"HTML_STRING1",nil),
client.aClientFirstName,
client.aClientLastName,
client.aClientEMail.length == 0? #"": client.aClientEMail,
client.aClientPrimaryPhone,
apptSelected.aServices,
fileURL];
}
else {
htmlString = [NSString stringWithFormat:NSLocalizedString(#"HTML_STRING2",nil),
client.aClientFirstName,
client.aClientLastName,
client.aClientPrimaryPhone,
apptSelected.aServices,
fileURL];
}
When I look at custImage in the XCode debugger, I see a different image from the previous image, which is correct. However, when it gets time to display the image at fileURL, it's a totally different image than custImage and is the same image that was displayed the first time!
UPDATE #2: I have figured out that fileURL has the correct image, but it is NOT being written to the device the second time (the first image is not being replaced).
UPDATE #3: this is the contents of htmlString that is displayed in the UIWebView popover:
<html><head><style type="text/css"> body {font-family: "Verdana"; font-size: 12;} </style></head><body>
<h2>Rolf Marsh</h2><p>phone: 213-555-1234<p>services: Art, Decals<p><img src="file:///private/var/mobile/Applications/FEE7159E-1FF8-4B94-A446-2A4C72E0AD41/tmp/custImage.png"/></body></html>
Any suggestions on how to fix this?
you never write the data to disk as far as I can see.
Only in the commented out section you attempt to.
Write it in between:
NSURL *tmpDirURL = [NSURL fileURLWithPath:NSTemporaryDirectory() isDirectory:YES];
NSURL *fileURL = [[tmpDirURL URLByAppendingPathComponent:#"custImage"] URLByAppendingPathExtension:#"png"];
//write
NSError*writeError = nil;
[client.aClientImage writeToURL:fileURL options:0 error:&writeError];
NSAssert(writeError==nil, writeError);
//read / use in the html or so
...
Dont forget to reload the web view or whatever you use to show the html
I figured it out... for others that are having the same problem, here is the code that works. Notice that I do NOT save it to a temporary file, since I already have the image in the Core Data entity. Here's the code:
-(void) showExistingAppointmentDetails: (AppointmentInfo *) apptSelected {
// make rectangle to attach popover
CGRect rectangle = CGRectMake( [apptSelected.aPosX floatValue], [apptSelected.aPosY floatValue],
[apptSelected.aPosW floatValue], [apptSelected.aPosH floatValue]);
// see if this is for staff; if so, don't display anything
if([apptSelected.aApptKey isEqual: #"Staff"])
return;
NSPredicate *predicate = ([NSPredicate predicateWithFormat: #"aClientKey == %#", apptSelected.aApptKey ]); // was aApptKey
ClientInfo *client = [ClientInfo MR_findFirstWithPredicate:predicate inContext:localContext];
UIImage *image = [UIImage imageWithData:client.aClientImage]; // image is good <---------
// write appointment info into html string
NSString *htmlString;
if(client.aClientEMail.length > 0) {
htmlString = [NSString stringWithFormat:NSLocalizedString(#"HTML_STRING1",nil),
client.aClientFirstName,
client.aClientLastName,
client.aClientEMail.length == 0? #"": client.aClientEMail,
client.aClientPrimaryPhone,
apptSelected.aServices,
[self htmlForPNGImage:image]];
}
else {
htmlString = [NSString stringWithFormat:NSLocalizedString(#"HTML_STRING2",nil),
client.aClientFirstName,
client.aClientLastName,
client.aClientPrimaryPhone,
apptSelected.aServices,
[self htmlForPNGImage:image]];
}
UIViewController* popoverContent = [[UIViewController alloc] init];
UIView* popoverView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 250, 300)];
popoverView.backgroundColor = [UIColor colorWithWhite:(CGFloat)1.0 alpha:(CGFloat)1.0]; // frame color?
popoverContent.view = popoverView;
//resize the popover view shown in the current view to the view's size
popoverContent.contentSizeForViewInPopover = CGSizeMake(250, 300);
// add the UIWebView for RichText
UIWebView *webView = [[UIWebView alloc] initWithFrame:popoverView.frame];
webView.backgroundColor = [UIColor whiteColor]; // change background color here
// add the webView to the popover
[webView loadHTMLString:htmlString baseURL:[NSURL URLWithString:nil]];
[popoverView addSubview:webView];
// if previous popoverController is still visible... dismiss it
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
}
//create a popover controller
popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverContent];
[popoverController presentPopoverFromRect:rectangle inView:self
permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
- (NSString *) htmlForPNGImage:(UIImage *) image {
NSData *imageData = UIImagePNGRepresentation(image);
NSString *imageSource = [NSString stringWithFormat:#"data:image/png;base64,%#",[imageData base64Encoding]];
return [NSString stringWithFormat:#"%#", imageSource];
}