I am using UITableView. And if there is no network connection then there will be exception thrown in viewDidload. My viewDidLoad function is:
#try {
NSLog(#"Request URL = %#",URLString);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL
URLWithString:URLString]];
NSData *response = [NSURLConnection sendSynchronousRequest:request
returningResponse:nil error:nil];
NSError *jsonParsingError = nil;
NSDictionary *tableData = [NSJSONSerialization JSONObjectWithData:response
options:0
error:&jsonParsingError];
// Grab whole data with data field in JSON
// responseArray = [tableData objectForKey:#"data"];
responseArray = [[NSMutableArray alloc]initWithArray:[tableData objectForKey:#"data"]];
for(int i = 0; i < responseArray.count; i++)
{
NSArray * tempArray = responseArray[i];
responseArray[i] = [tempArray mutableCopy];
}
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setFrame:CGRectMake(280.0, 0.0, 40.0, 40.0)];
[btn setImage:[UIImage imageNamed:#"sort_icon.png"] forState:UIControlStateNormal];
[btn addTarget:self action:#selector(showActionSheet) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *barbutton = [[UIBarButtonItem alloc]initWithCustomView:btn];
self.navigationItem.rightBarButtonItem = barbutton;
}
#catch (NSException *exception)
{
exceptionOccured = YES;
NSLog(#"Exception Ocurred");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Error in connectivity" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
In cellForRowAtIndexPath I am doing this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
#try {
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc] init];
tempDict = [responseArray objectAtIndex:indexPath.row];
return cell;
}
#catch (NSException *exception)
{
NSLog(#"Error in CEll Create");
NSLog(#"Draw Alert");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Error in connectivity" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
and in AlertViewDelegate Function I am doing
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
[self.navigationController popViewControllerAnimated:YES];
}
Now problem is that it is not showing the Alert whenever there is an exception and re-throws the exception and shows the Error
Thread 1: EXC_BAD_ACCESS(code=2, address=0x2)
Any help will be appreciated...
You should avoid throwing exceptions in your code.
First of all you could use Reachability Class to determine whether or not an active internet connection is available.
I would definitively recommend using the NSURLConnectionDelegate protocol for URL connections. So you can use the better asynchronous programming style.
The problem is somewhere else. When - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath is called it means the system needs the tableView to be reloaded. Therefore, you should not check for data inside that function. When you enter this function, you should be sure that your data is ok.
What you have to do is firstly check your data in a specific function:
-(void)CheckData(NSArray *responseArray) {
#try {
//Retrieve your data & check if its valid
self.dataArray = responseArray;
[self.tableView reloadData];
}
#catch (NSException *exception)
{
NSLog(#"Error in check Data");
NSLog(#"Draw Alert");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Error in connectivity" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
Then, implement your data source delegates:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.dataArray count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewStylePlain reuseIdentifier:CellIdentifier] autorelease] ;
}
//TODO: Init your cell using your self.dataArray content
return cell;
}
I would recommend import this SystemConfiguration framework and use the same. This will check whether network connection is available or not. Below is the simple code:-
#import <SystemConfiguration/SystemConfiguration.h>
-(void)yourMethod
{
SCNetworkConnectionFlags flags = 0;
if (yourhostname && [yourhostname length] > 0)
{
flags = 0;
BOOL found = NO;
SCNetworkReachabilityRef reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [yourhostname UTF8String]);
if (reachabilityRef)
{
found = SCNetworkReachabilityGetFlags(reachabilityRef, &flags)
&& (flags & kSCNetworkFlagsReachable)
&& !(flags & kSCNetworkFlagsConnectionRequired);
CFRelease(reachabilityRef);
reachabilityRef = NULL;
}
if (found)
{
NSLog(#"Connection available");
}
else
{
NSLog(#"Connection not available");
}
}
Related
I have a page where we select recipients (who are friends) to send an image to. but if no recipients are selected we can still send the message. i want it so that if no recipients are selected we can show a UIAlertView. for me its not working when i try to display an alert please see my code below.
.h
#property (nonatomic, strong) NSArray *friends;
#property (nonatomic, strong) PFRelation *friendsRelation;
#property (nonatomic, strong) NSMutableArray *recipients;
- (IBAction)send:(id)sender;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
self.recipients = [[NSMutableArray alloc] init];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.friendsRelation = [[PFUser currentUser] objectForKey:#"friendsRelation"];
PFQuery *query = [self.friendsRelation query];
[query orderByAscending:#"username"];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error %# %#", error, [error userInfo]);
}
else {
self.friends = objects;
[self.tableView reloadData];
}
}];
//display camera modally etc......
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
cell.textLabel.text = user.username;
if ([self.recipients containsObject:user.objectId]) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
PFUser *user = [self.friends objectAtIndex:indexPath.row];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[self.recipients addObject:user.objectId];
}
else {
cell.accessoryType = UITableViewCellAccessoryNone;
[self.recipients removeObject:user.objectId];
}
NSLog(#"%#", self.recipients);
}
here is the part where i try to display my alert
- (IBAction)send:(id)sender {
if (!self.recipients) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"Select some friends" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
} else {
[self uploadMessage];
//we upload the message in method to parse.com
}
}
it does not seem to show for some reason so we can send messages to no one. how can i show the alert view?
Try this. Check objects of recipients is equal to 0 or not.
- (IBAction)send:(id)sender {
if ([self.recipients count]==0) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"Select some friends" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
} else {
[self uploadMessage];
//we upload the message in method to parse.com
[self.tabBarController setSelectedIndex:1];
}
}
The problem with your code is the condition that you are checking::
if (!self.recipients)
here self.recipients will always give true value as it will look for memory address of this object, which you have assigned to it in your viewDidLoad method.
You have to check for the count of the array in your scenario.
I have a left slide menu powered by AMSlideMenu library that displays a tableview with menu items.
AMSlideMenuLeftTableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
cell.textLabel.font = [UIFont fontWithName:#"HelveticaNeue-Light" size:18];
cell.textLabel.textColor = [UIColor whiteColor];
cell.backgroundColor = [UIColor clearColor];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"loggedUser"] != nil) {
if (indexPath.row == 0) { cell.textLabel.text = [NSString stringWithFormat:#"Hi, %#", [[NSUserDefaults standardUserDefaults] objectForKey:#"loggedUser"]]; }
if (indexPath.row == 1) { cell.textLabel.text = #"Contact"; }
} else {
if (indexPath.row == 0) { cell.textLabel.text = #"Log in"; }
if (indexPath.row == 1) { cell.textLabel.text = #"Contact"; }
}
}
LoginViewController.m
- (IBAction)loginButtonPressed:(id)sender {
if(![self.usernameTextField.text isEqual: #""] && ![self.passwordTextField.text isEqual:#""]){
for (UITextField *eachTextfield in self.view.subviews)
[eachTextfield resignFirstResponder];
PFQuery *query = [PFQuery queryWithClassName:#"UsersClass"];
[query whereKey:#"Username" equalTo:self.usernameTextField.text];
[query whereKey:#"Password" equalTo:self.passwordTextField.text];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
// The find succeeded.
if (objects.count > 0){
[self dismissViewControllerAnimated:YES completion:nil];
//Get the username and save it as "loggedUser" for later use
[[NSUserDefaults standardUserDefaults] setObject:self.usernameTextField.text forKey:#"loggedUser"];
[[NSUserDefaults standardUserDefaults] synchronize];
[self performSegueWithIdentifier:#"showDetail" sender:self];
}else{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Error" message:NSLocalizedString(#"The username or password are incorrect", nil) delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
} else {
// Log details of the failure
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}else{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Error" message:NSLocalizedString(#"Both fields are required", nil) delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
However, after logging in, the menu does not refresh and keeps displaying the wrong cell.textLabel.text. It works if I close and open again the application, but obviously there has to be another way of solving this.
I have tried [tableView reloadData] but this does not work. I have tried it on viewDidLoad and viewWillAppear without success.
Appreciate any help. Thanks
Here is what you need to do. In your loginButtonPressed method in case of a successful login post a notification like this:
NSNotification *loginNotification = [NSNotification notificationWithName:#"USER_DID_LOGIN" object:nil];
[[NSNotificationCenter defaultCenter] postNotification:loginNotification];
In your view controller with tableView do this:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(updateOnLogin:) name:#"USER_DID_LOGIN" object:nil];
}
- (void)updateOnLogin:(NSNotification*)notification
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
});
}
Whenever user logs in successfully, your view controller will receive a notification, and it will reload the tableView.
In my UITableViewController there are custom cells populated from JSON. Each cell has a UILabel showing a text value (#"valoracion"). When the user selects a row, a detail view from the cell object is shown. At this detail view, the user can change the value of valoracion. If the user goes back to the UITableViewController, valoracion should show the new value, but actually it shows the old value.
What should I do to update valoracion in the UITableViewController, when the user goes back from the detail view to the UITableViewController.
UPDATED***
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell =[tableView dequeueReusableCellWithIdentifier:#"Cell"];
if (cell ==nil){
cell = [[CustomCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:#"Cell"];
}
//cell.backgroundColor = [UIColor clearColor];
cell.nombreEmpresaLabel.text = [[categorias objectAtIndex:indexPath.row] objectForKey:#"nombreEmpresa"];
//[[cell contentView] setBackgroundColor:[UIColor clearColor]];
//cell.textLabel.backgroundColor = nil;
// cell.detailTextLabel.backgroundColor=nil;
cell.textLabel.textColor = [UIColor whiteColor];
cell.direccionEmpresaLabel.text= [[categorias objectAtIndex:indexPath.row] objectForKey:#"direccionEmpresa"];
NSMutableString *logo = [[NSMutableString alloc]initWithString:#"http://mujercanariasigloxxi.appgestion.eu/logos/"];
NSString *imageURL = [[categorias objectAtIndex:indexPath.row] objectForKey:#"strImagen"];
cell.meGustaHits.text = [[categorias objectAtIndex:indexPath.row] objectForKey:#"valoracionEmpresa"];
if(imageURL != nil && ![imageURL isEqual:[NSNull null]])
{
[logo appendString:imageURL];
NSURL *logoURL = [NSURL URLWithString:logo];
NSData *logoData = [NSData dataWithContentsOfURL:logoURL];
cell.logoImage.image = [UIImage imageWithData:logoData];
}
else{
cell.logoImage.image = [UIImage imageNamed:#"icono80"];
}
return cell;
}
Inside viewDidLoad method:
//URL definition where php file is hosted
int categoriaID = [[categoriaDescription objectForKey:#"idCategoria"] intValue];
NSString *string = [NSString stringWithFormat:#"%d", categoriaID];
NSLog(#"CATEGORIA ID STGRING %#",string);
NSMutableString *ms = [[NSMutableString alloc] initWithString:#"http://mujercanariasigloxxi.appgestion.eu/app_php_files/empresaslist.php?id="];
[ms appendString:string];
// URL request
NSLog(#"URL = %#",ms);
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:ms]];
//URL connection to the internet
[[NSURLConnection alloc]initWithRequest:request delegate:self];
And now the JSON delegate methods and didSelecRowAtIndexpath method:
//methods to perform the connection and population of data
-(void)connection: (NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
data = [[NSMutableData alloc]init];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)thedata
{
[data appendData:thedata];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//if data received network indicator not visible
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
//array waterfalls populated via JSON from database
categorias = [NSJSONSerialization JSONObjectWithData:data options:nil error:nil];
NSLog(#"THE DA TA &#",categorias);
[self.tableView reloadData];
}
//only in case of error
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
UIAlertView *errorView = [[UIAlertView alloc]initWithTitle:#"Error" message:#"The download could not complete - please make sure you are connected to eithre 3G or WiFi" delegate:nil cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[errorView show];
//if no connection network indicator not visible
[UIApplication sharedApplication].networkActivityIndicatorVisible=NO;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DetalleEmpresaViewController *detailViewController =[self.storyboard instantiateViewControllerWithIdentifier:#"detailEmpresaViewController"];
detailViewController.title =[[categorias objectAtIndex:indexPath.row]objectForKey:#"idCategoria"];
detailViewController.detalleDescription = [categorias objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailViewController animated:YES];
}
Try call [tableview reloadData] method and make sure that you have correct implementation of tableview delegate methods.
If place where you change and save your JSON is another, than tableViewController, then put reloadData method in viewDidAppear of tableViewController class. If you saving JSON in other method of same tableViewController, then place reloadData in last line of this method.
I added a Searchbar and Search Display Controller to my iPad app that use localSearch. I believe I implemented the delegates correctly. The search works fine and displays the results but the issues is that these results start in the second cell. The first cell in the popup display being empty. I double checked to see if the map items count and contents were correct and they were.
The code:
- (void) searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
if (![self connected]) {
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Cannot Connect",nil)
message:NSLocalizedString(#"Please make sure you are connected to the internet and try again.",nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
}
else if ([mainToolbar isHidden])
{
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Search Unavailable",nil)
message:NSLocalizedString(#"Please make sure you aren't drawing an AOI or using a tool and then try again.",nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
}
else {
// Cancel any previous searches.
[localSearch cancel];
// Perform a new search.
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = self.searchBar.text;
request.region = self.mapView.region;
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
localSearch = [[MKLocalSearch alloc] initWithRequest:request];
[localSearch startWithCompletionHandler: ^(MKLocalSearchResponse *response, NSError *error){
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
if ([response.mapItems count] == 0)
{
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"No Results",nil)
message:nil
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
if (error != nil)
{
[[[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Map Error",nil)
message:NSLocalizedString(#"Sorry.", nil)
delegate:nil
cancelButtonTitle:NSLocalizedString(#"OK",nil) otherButtonTitles:nil] show];
return;
}
results = response;
[self.searchDisplayController.searchResultsTableView reloadData];
}
];
}
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [results.mapItems count];
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *IDENTIFIER = #"SearchResultsCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:IDENTIFIER];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:IDENTIFIER];
}
MKMapItem *item = results.mapItems[indexPath.row];
cell.textLabel.text = item.name;
cell.detailTextLabel.text = item.placemark.addressDictionary[#"Street"];
return cell;
}
Here is a screenshot of the issue.
The first row contains the table header.
So I was able to get the text fields to populate as subviews in my table view for the login. Now I want to reference the username text field and password text field in my login action however the action can not find the variables of the text fields (username and password) PLEASE HELP! This has been driving me nuts! Here is my code.
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *CellIdentifier = [self.menuItems objectAtIndex:indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (indexPath.row == 0) {
UITextField *username = [[UITextField alloc] init];
username.frame = CGRectMake(10, 6, 280, 30);
username.placeholder = #"Username";
cell.tag = 0;
[username addTarget:self action:#selector(login:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:username];
} else {
UITextField *password = [[UITextField alloc] init];
password.frame = CGRectMake(10, 6, 280, 30);
password.placeholder = #"Password";
cell.tag = 1;
[password addTarget:self action:#selector(login:) forControlEvents:UIControlEventTouchUpInside];
[password setSecureTextEntry:YES];
[cell.contentView addSubview:password];
}
return cell;
}
As you can see I created the text fields username and password. However the variables are not being referenced in the action! Anytime the word "username" or "password" shows up, it says "use of undeclared identifier username"/"use of undeclared identifier password". Your help will be greatly appreciated!
-(IBAction)login:(id)sender {
if ([username.text isEqualToString:#""] || [password.text isEqualToString:#""]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!" message:#"Please fill in all the fields!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
{
NSString *strURL = [NSString stringWithFormat:#"http://www.mysite.com/myfile.php?username=%#&password=%#",username.text, password.text];
NSData *dataURL = [NSData dataWithContentsOfURL:[NSURL URLWithString:strURL]];
NSString *strResult = [[NSString alloc] initWithData:dataURL encoding:NSUTF8StringEncoding];
NSLog(#"%#", strResult);
NSString *cont11 = [NSString stringWithFormat:#"http://www.mysite.com/myfile.php?username=%#&password=%#",username.text, password.text];
NSData *cont12 = [NSData dataWithContentsOfURL:[NSURL URLWithString:cont11]];
NSString *cont13 = [[NSString alloc] initWithData:cont12 encoding:NSUTF8StringEncoding];
NSLog(#"%#", cont13);
if ([strResult isEqualToString:#"1"])
{
UIStoryboard *mainStoryboard=[UIStoryboard
storyboardWithName:#"Storyboard" bundle:nil];
AdminPanel *mainView=[mainStoryboard
instantiateViewControllerWithIdentifier:#"admin"];
mainView.modalTransitionStyle=UIModalTransitionStyleCoverVertical;
[self presentViewController:mainView animated:YES completion:nil];
}else
{
// invalid information
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!" message:#"You must have entered something wrong! Try again!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
return;
}
}
}
You must create the variables under #interface in your .m file:
#interface YourViewController ()
{
UITextField *username;
UITextField *password;
}
Then take out "UITextField" when you init these variables.