2013-05-09 3 views
0

Я работаю над проектом, который имеет простой табличный вид с подробным представлением.Сохранение данных в существующем plist

Источник данных - plist. Я стараюсь, чтобы пользовательский ввод сохранялся в plist и отображался в виде таблицы. я создал контроллер добавления, который представляется и отклоняется модально и имеет два текстовых поля, которые позволяют пользователю добавлять имя города и имя состояний, а также текстовое поле для ввода описания.

Проблема: как сохранить эти данные в моем существующем plist и показать его в tableview. Вот мой код для представления таблицы:

@implementation TableViewController 

@synthesize content, searchResults; 



- (id)initWithStyle:(UITableViewStyle)style 
{ 
self = [super initWithStyle:style]; 
if (self) { 
    // Custom initialization 
} 
return self; 
} 

- (void)viewDidLoad 
{ 
[super viewDidLoad]; 

content = [[NSArray alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Data" ofType:@"plist"]]; 
} 

- (IBAction)add; 
{ 
AddViewController* controller = [[AddViewController alloc] init]; 
[self presentViewController:controller animated:YES completion:nil]; 
} 

- (void)didReceiveMemoryWarning 
{ 
[super didReceiveMemoryWarning]; 
// Dispose of any resources that can be recreated. 
} 

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
{ 

if (tableView == self.searchDisplayController.searchResultsTableView) { 
    return [self.searchResults count]; 

} else { 
    return [self.content count]; 

} 
} 

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope 
{ 

NSPredicate *resultPredicate = [NSPredicate predicateWithFormat: @"SELF['city'] BEGINSWITH[c] %@ ", searchText]; 

searchResults = [[content filteredArrayUsingPredicate:resultPredicate] retain]; 
} 

-(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString 
{ 
[self filterContentForSearchText:searchString 
          scope:[[self.searchDisplayController.searchBar scopeButtonTitles] 
            objectAtIndex:[self.searchDisplayController.searchBar 
               selectedScopeButtonIndex]]]; 

return YES; 
} 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
static NSString *CellIdentifier = @"Cell"; 
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
if (cell == nil) { 
    cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: CellIdentifier] autorelease]; 
} 

if (tableView == self.searchDisplayController.searchResultsTableView) { 
    cell.textLabel.text = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"city"]; 
    cell.detailTextLabel.text = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"state"]; 
    cell.imageView.image = [UIImage imageNamed:[[self.searchResults objectAtIndex:indexPath.row] valueForKey:@"cityImage"]]; 
} else { 
    cell.textLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:@"city"]; 
    cell.detailTextLabel.text = [[self.content objectAtIndex:indexPath.row] valueForKey:@"state"]; 
    cell.imageView.image = [UIImage imageNamed:[[self.content objectAtIndex:indexPath.row] valueForKey:@"cityImage"]]; 

} 

return cell; 
} 



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
if (tableView == self.searchDisplayController.searchResultsTableView) { 
    [self performSegueWithIdentifier: @"showDetails" sender: self]; 
} 
} 

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender 

{ 

if ([segue.identifier isEqualToString:@"showDetails"]) { 

    NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; 
    DetailViewController *DVC = [segue destinationViewController]; 

    if ([self.searchDisplayController isActive]) { 

     DVC.cityImageString = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"cityImage"]; 
     DVC.cityTextString = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"cityText"]; 
     DVC.cityNameString = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"city"]; 
     DVC.stateNameString = [[searchResults objectAtIndex:indexPath.row] valueForKey:@"state"]; 
    } else { 

     DVC.cityImageString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"cityImage"]; 
     DVC.cityTextString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"cityText"]; 
     DVC.cityNameString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"city"]; 
     DVC.stateNameString = [[self.content objectAtIndex:indexPath.row] valueForKey:@"state"]; 
    } 

} 
} 

и вот код для addViewController.h:

@interface AddViewController : UIViewController <UINavigationControllerDelegate,UIImagePickerControllerDelegate>{ 

IBOutlet UITextField *cityTextField; 
IBOutlet UITextField *stateTextField; 
IBOutlet UITextView *cityDescription; 

UIImagePickerController* imagePicker; 
} 
@property (nonatomic, copy) NSString* name; 
@property (nonatomic, copy) NSString* description; 
@property (nonatomic, strong) UIImage* image; 
@property (nonatomic, retain) IBOutlet UINavigationBar* navigationBar; 

@property (nonatomic, strong) UITextField *cityTextField; 
@property (nonatomic, strong) UITextField *stateTextField; 
@property (nonatomic, strong) UITextView *cityDescription; 

@property (nonatomic, strong) IBOutlet UIButton* choosePhotoButton; 
@property (nonatomic, strong) IBOutlet UIButton* takePhotoButton; 



- (IBAction)save; 
- (IBAction)cancel; 

- (IBAction)choosePhoto; 
- (IBAction)takePhoto; 

@end 

и наконец-контроллер добавить .m

@implementation AddViewController 
@synthesize cityTextField, stateTextField, cityDescription; 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
if (self) { 
    // Custom initialization 
} 
return self; 
} 

- (IBAction)save 
{ 
// Make sure the user has entered at least a recipe name 
if (self.cityTextField.text.length == 0) 
{ 
    UIAlertView* alertView = [[UIAlertView alloc] 
           initWithTitle:@"Whoops..." 
           message:@"Please enter a city name" 
           delegate:nil 
           cancelButtonTitle:@"OK" 
           otherButtonTitles:nil]; 

    [alertView show]; 
    [alertView release]; 
    return; 
} 

if (self.stateTextField.text.length == 0) 
{ 
    UIAlertView* alertView = [[UIAlertView alloc] 
           initWithTitle:@"Whoops..." 
           message:@"Please enter a city name" 
           delegate:nil 
           cancelButtonTitle:@"OK" 
           otherButtonTitles:nil]; 

    [alertView show]; 
    [alertView release]; 
    return; 
} 
// Make sure the user has entered at least a recipe name 
if (self.cityDescription.text.length == 0) 
{ 
    UIAlertView* alertView = [[UIAlertView alloc] 
           initWithTitle:@"Whoops..." 
           message:@"Please enter city description" 
           delegate:nil 
           cancelButtonTitle:@"OK" 
           otherButtonTitles:nil]; 

    [alertView show]; 
    [alertView release]; 
    return; 
} 

self.name = self.cityTextField.text; 
self.name = self.stateTextField.text; 
self.description = self.cityDescription.text; 


if ([[self parentViewController] respondsToSelector:@selector(dismissViewControllerAnimated:)]){ 

    [[self parentViewController] dismissViewControllerAnimated:YES completion:nil]; 

} else { 

    [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; 
} 
} 

- (IBAction)cancel { 
{ 

    if ([[self parentViewController] respondsToSelector:@selector(dismissModalViewControllerAnimated:)]){ 

     [[self parentViewController] dismissViewControllerAnimated:YES completion:nil]; 

    } else { 

     [[self presentingViewController] dismissViewControllerAnimated:YES completion:nil]; 
    } 
} 
} 

- (IBAction)choosePhoto 
{ 
// Show the image picker with the photo library 
imagePicker = [[UIImagePickerController alloc] init]; 
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; 
imagePicker.delegate = self; 
imagePicker.allowsEditing = YES; 
[self presentViewController:imagePicker animated:YES completion:nil]; 
} 

- (IBAction)takePhoto { 

UIImagePickerController *picker = [[UIImagePickerController alloc] init]; 
//picker.delegate = self; 
picker.allowsEditing = YES; 
picker.sourceType = UIImagePickerControllerSourceTypeCamera; 

[self presentViewController:picker animated:YES completion:NULL]; 

} 

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 

UITouch *touch = [touches anyObject]; 
if ([cityDescription isFirstResponder] && [touch view] != cityDescription) { 

    [cityDescription resignFirstResponder]; 
} 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

[cityTextField resignFirstResponder]; 
[stateTextField resignFirstResponder]; 
} 

#pragma mark - 
#pragma mark UIImagePickerControllerDelegate 

- (void)imagePickerController:(UIImagePickerController*)picker  didFinishPickingMediaWithInfo:(NSDictionary*)info 
{ 
// We get here when the user has successfully picked an image. 
// Put the image in our property and set it on the button. 

if (imagePicker) { 
    self.image = [info objectForKey:UIImagePickerControllerEditedImage]; 
    [self.choosePhotoButton setImage:self.image forState:UIControlStateNormal]; 
} else { 

    if (picker) { 
     self.image = [info objectForKey:UIImagePickerControllerEditedImage]; 
     [self.takePhotoButton setImage:self.image forState:UIControlStateNormal]; 
    } 
} 

[self dismissViewControllerAnimated:YES completion:nil]; 
[imagePicker release]; 
imagePicker = nil; 
} 

- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker 
{ 
[self dismissViewControllerAnimated:YES completion:nil]; 
[imagePicker release]; 
imagePicker = nil; 
} 
- (void)viewDidLoad 
{ 
[super viewDidLoad]; 
// Do any additional setup after loading the view. 
} 

- (void)didReceiveMemoryWarning 
{ 
[super didReceiveMemoryWarning]; 
// Dispose of any resources that can be recreated. 
} 

@end 

я знаю, что есть тонны почти подобных вопросов и, поверьте, я посмотрел на так много из них, и я думаю, что я нахожусь на стене с этим, и я не могу подумать надлежащего способа сделать это. это может быть так просто, но для моей жизни я не могу это понять, и поэтому я пытаюсь обратиться за помощью. Я по-настоящему ценю любую помощь, которую я могу получить. если нужно, я могу разместить образец проекта на git-хабе для удобства доступа. также проект построен в ios 6 и последнем Xcode.

P.S. вот ссылка на проект на git hub: https://github.com/AdrianPhillips/TableSearch

ответ

0

Так же, как каждый указал, что вы не можете писать в plist, который находится в вашем главном комплекте. Вам нужно скопировать его из пакета в каталог вашего документа приложения. Затем вы можете просто запустить и записать путь в каталог документов. Другая проблема, с которой вы столкнулись, заключается в том, что ничто не передает новые данные из AddViewController обратно в TableViewController. Вы должны создать протокол и делегировать для своего AddViewController.

Для получения подробной информации о подробностях смотрите мой запрос на тягу на GitHub.
https://github.com/GayleDDS/TableSearch.git

+0

@ Gayle, спасибо за вклад. делегат - хороший подход, и он сохраняет данные, но не все. изображение не сохраняется. это одна из важных частей моего вопроса. У bob cromwell был подход с сохранением копии plist, и он также работает, но он не сохраняет изображение, выбранное из библиотеки и взятое с камеры. вы можете помочь с частью сохранения изображения, которая полностью ответит на вопрос. большое спасибо –

+0

@CodeMonkey Я добавил сохранение и чтение изображений. Вчера вечером устала и ленилась. Приветствия. см. https://github.com/GayleDDS/TableSearch.git – GayleDDS

+0

видел дополнение. блестящий. но один вопрос. в представлении segue to detail не отображается изображение, добавленное в подробном представлении. любая идея почему? –

1

Я не могу найти ваш код, который выполняет фактическую «экономию» работы. Думаю, это должно быть в делегате UIAlertView, верно? И ты не сказал нам, в чем твоя проблема. Следующий код может быть, что вы ищете.

[содержание WriteToFile: Filepath атомарно: YES]

Еще одно напоминание: вы не должны сохранить PLIST назад к главному расслоению, сохраните его документы или кэш или другую папку.

+0

Это вопрос bob, у меня нет метода сохранения. Я не могу понять, как сохранить строки в plist, которые у меня есть, и показать их в существующем табличном представлении. Я разместил проект на github, и ссылка находится в комментариях к другому ответу. Будете ли вы принцем и взгляните на проект и поможете мне реализовать методы, которые я ищу, пожалуйста. –

+0

@CodeMonkey Я отправляю запрос на получение вашего репо. Кстати, я думаю, вы должны выяснить, как это сделать самостоятельно. –

+0

@ Боб спасибо за код, теперь я понимаю его лучше. один вопрос, но как перезагрузить представление таблицы, чтобы показать вновь введенные данные? –

0

Сначала вы должны скопировать plist в папку Documents. Вы не можете редактировать его в исходной папке приложения. Вы можете использовать этот класс для этого:

- (void) CreatePlistCopyInDocuments:(NSString *)plistName { 
    // First, test for existence. 
    BOOL success; 

    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSError *error; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *writablePath = [documentsDirectory stringByAppendingPathComponent:plistName]; 
    success = [fileManager fileExistsAtPath:writablePath]; 

    if (success) { 
     return; 
    } 

    // The writable file does not exist, so copy from the bundle to the appropriate location. 
    NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:plistName]; 
    success = [fileManager copyItemAtPath:defaultPath toPath:writablePath error:&error]; 
    if (!success) { 
     NSAssert1(0, @"Failed to create writable file with message '%@'.", [error localizedDescription]); 
    } 
} 

Вы должны просто передать ему имя plist. Тогда вы должны загрузить его в какой-то NSMutableDictionary так:

NSString *documents = [NSHomeDirectory() stringByAppendingString:@"/Documents"]; 
      NSString *plistInDocuments = [documents stringByAppendingPathComponent:@"UserData.plist"]; 
      NSMutableDictionary *plistData = [[NSMutableDictionary alloc]initWithContentsOfFile:plistInDocuments]; 

После обновления значения для словаря, вы должны записать файл обратно в документы, как это:

[plistData writeToFile:plistInDocuments atomically:YES]; 
Смежные вопросы