AppDelegate Доступ из разных классов, из RootController.m
Моя проблема заключается в получении информации от контроллера (который является моим rootViewController) в другое представление. Пытаясь получить доступ к нему через делегат приложения, я не смог заставить его работать. Я нашел, как это сделать, но этот inturn создал другую проблему получения представления внутри модального контроллера представления, чтобы фактически отобразить данные. Ниже я разместил как информацию appDelegate, так и код решения NSMutable Dictionary для тех, кому тоже может понадобиться помощь.
Больше недели я пытался решить эту проблему самостоятельно. Моя проблема закончилась тем, как получить доступ к appDelegate, поэтому у меня возникла проблема с NSDictionary. Так что, в конце концов, проблема была не в NSDictionary, хотя, если бы я пошел дальше, это была бы проблема, я уверен.
Во-первых, я хотел бы поблагодарить TechZen за то, что он помог мне увидеть, что я закончил программировать, и указать мне правильное направление.
Вот что я узнал.
Назначьте вашу переменную в appDelegate.
AppDelegate.h
@interface AppDelegate : NSObject < UIApplicationDelegate, UINavigationControllerDelegate >
{
UIWindow *window;
UINavigationController *navController;
// Array to store the Makers Objects
NSMutableArray *makers;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navController;
@property (retain, nonatomic) NSMutableArray *makers;
@end
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
makers = [[NSMutableArray alloc] init] ;
}
В ViewController.m назначьте переменную appDelegate. Я сделал это внутри функции tableView didSelectRowAtIndexPath.
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
// The line below loads it into the variable, the one above takes it and makes it available for other view Controllers.
Maker *maker = (Maker *)[appDelegate.makers objectAtIndex:indexPath.row];
// the combination of the above and below also loads the information into another array in this view controller, defined in an NSObject Controller called Maker (.h and .m files)
maker = [self.Makers objectAtIndex:indexPath.row];
Теперь в вашем контроллере представления вы хотите загрузить переменную из appDelegate, установите ее следующим образом.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
#import "Maker.h"
@class AppDelegate;
@interface DetailsViewController : UIViewController
{
AppDelegate *dappDelegate;
DetailsViewController *detailsView;
IBOutlet UITextView *makerDescription;
}
@property (retain, nonatomic) AppDelegate *dappDelegate;
@property (nonatomic, retain) DetailsViewController *detailsView;
@property (nonatomic, retain) IBOutlet UITextView *makerDescription;
@end
и в файле viewController.m;
#import "DetailsViewController.h"
#import "AppDelegate.h"
@synthesize dappDelegate;
- (void)viewWillAppear:(BOOL)animated // or ViewDidLoad not sure which is better.
dappDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate];
NSString *newLocalVariable = [dappDelegate.makers description];
NSLog(@"newLocalVariable: %@", [dappDelegate.makers description]);
// This is for verifying you have it loaded. 'description' is defined in the Maker NSObject, see below for those files, and above for where it was assigned originally
..... и назначьте это на то, что вы хотите сейчас!
Я надеюсь, что это помогает всем. В этот момент вы можете поместить NSArray в NSDictionary, но теперь доступ осуществляется с ключами и значениями, так что на данный момент доступ к нему немного сложнее, но, конечно, его преимущества. Я просто не могу пока полностью отказаться от этого и отказался от этого метода, чтобы просто использовать NSArray.
Ниже приведен образец файла Makers h and m, который вы также можете увидеть.
Maker.h
@interface Maker : NSObject
{
NSString *name;
NSString *address;
NSString *city;
NSString *postalcode;
NSString *country;
NSString *phonenumber;
NSString *email;
NSString *description;
NSString *services;
NSString *website;
}
@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *address;
@property (nonatomic, copy) NSString *city;
@property (nonatomic, copy) NSString *postalcode;
@property (nonatomic, copy) NSString *country;
@property (nonatomic, copy) NSString *phonenumber;
@property (nonatomic, copy) NSString *email;
@property (nonatomic, copy) NSString *description;
@property (nonatomic, copy) NSString *services;
@property (nonatomic, copy) NSString *website;
- (id)initWithName:(NSString *)n address:(NSString *)a city:(NSString *)c postalcode:(NSString *)z country:(NSString *)o phonenumber:(NSString *)p email:(NSString *)e description:(NSString *)d services:(NSString *)s website:(NSString *)w;
@end
и его файл Maker.m;
#import "ViolinMaker.h"
@implementation Maker
@synthesize name, address, city, postalcode, country, phonenumber, email, description, services, website;
- (id)initWithName:(NSString *)n address:(NSString *)a city:(NSString *)c postalcode:(NSString *)z country:(NSString *)o phonenumber:(NSString *)p email:(NSString *)e description:(NSString *)d services:(NSString *)s website:(NSString *)w;
{
self.name = n;
self.address = a;
self.city = c;
self.postalcode = z;
self.country = o;
self.phonenumber = p;
self.email = e;
self.description = d;
self.services = s;
self.website = w;
return self;
}
@end
Я надеюсь, что это поможет другим разобраться в этом, поскольку это действительно стоило мне много времени, и я надеюсь, что вы можете немного узнать из того, что я узнал.
С уважением, Кирк
1 ответ
Я не вижу никакой точки, где вы населяете selectedMaker
ивар в DetailsViewController
с данными из `selectedMaker'делегата приложения. То, что они имеют одинаковое имя, не означает, что они используют одни и те же данные.
Вам необходимо назначить или скопировать значения из делегата приложения в контроллер представления. Быстрый и грязный способ сделать что-то вроде:
@implementation DetailsViewController
...
-(void) viewDidLoad{
//selectedMaker=[[UIApplication sharedApplication] selectedMaker]; <-- this is wrong
//Edit, this is the correct call to app delegate
selectedMaker=[[[UIApplication sharedApplication] delegate] selectedMaker];
}
Edit01:
Итак... по предложению TechZen я попытался переместить мой NSDictionary из моего RootViewController.
(1) Я не уверен, почему у вас есть SelectedMaker
класс того, что он должен выполнить. Вы, кажется, перепутали класс с NSMutableDictionary
, У класса нет видимой причины возвращать словарь, содержащий значения его собственных iVars. Это полностью избыточно. У вас уже есть класс с именем ViolinMaker
который инкапсулирует все данные для каждой записи производителя скрипки.
(2) Методы инициализации для SelectedMaker
не реализованы правильно. Похоже, вам нужно позвонить -[SelectedMaker initWithsName:..]
прежде чем позвонить -[SelectedMaker init]
в противном случае init не имеет ни малейшего понятия, что это за ключи.
(3) В любом случае, в didSelectRow
метод, вы на самом деле не инициализируете экземпляр SelectedMaker
, Эта строка:
SelectedMaker *selectedMaker = [[[NSMutableDictionary alloc]retain] initWithObjects: objects forKeys: keys];
Не создает экземпляр SelectedMaker
а скорее NSMutableDictionary
и более или менее бросить его на SelectedMaker
учебный класс. Вот почему вы получаете предупреждение компилятора из цикла for.
(4) Я не вижу необходимости в SelectedMaker
класс вообще. Эти строки:
ViolinMakerAppDelegate *appDelegate = (ViolinMakerAppDelegate *)[[UIApplication sharedApplication] delegate];
ViolinMaker *violinMaker = (ViolinMaker *)[appDelegate.violinMakers objectAtIndex:indexPath.row];
violinMaker = [self.filteredViolinMakers objectAtIndex:indexPath.row];
Покажите, чтобы предоставить вам всю информацию, необходимую для заполнения какой-либо конкретной строки в вашей таблице или в подробном представлении. Вы можете использовать эти три строки в любом представлении, в котором вам нужен доступ к данным в appDelegate.violinMakers'. The
violinMaker`объект содержит все необходимые данные.
Я думаю, что вы делаете это более сложным, чем это должно быть. Все, что вам нужно, это (A) класс, который инкапсулирует данные для каждой записи, извлеченной из вашего SQL. В этом случае похоже, что ViolinMaker делает это. (B) Вам нужен массив (или другая коллекция) в делегате приложения для хранения нескольких экземпляров ViolinMaker. (C) Вам нужен код в каждом viewcontroller, который будет обращаться к массиву / коллекции в делегате приложения, чтобы viewcontroller мог выбирать необходимые ему экземпляры ViolinMaker.
Edit02:
Нет, я не могу использовать эти 3 строки, поскольку objectAtIndex:indexPath.row доступен только внутри функции didSelectRow. Что означает, что мне придется реконструировать таблицу и все ее данные.
Вы просто определяете словарь один раз как переменную экземпляра в вашем делегате приложения. Таким образом, у вас будет изменяемый словарь, где каждое значение ViolinMaker
и каждый ключ был некоторым атрибутом изготовителя скрипки, таким как имя. Давайте назовем это violinMakersDict
Затем в любом месте вашего приложения вы можете получить доступ к словарю, сначала вызвав делегат приложения и получив доступ к violinMakersDict.
Чтобы заполнить таблицу, вам нужно извлечь некоторые значения в виде массива. Скорее всего, вы бы взяли ключи, которые являются именами скрипачей. Затем вы сортируете массив по алфавиту, а затем заполняете каждую строку значением массива со значением index.row.
Аналогичным образом, если вам нужно добавить данные в одном представлении, вы можете записать в violinMakersDict
а затем получить доступ к этим данным из другого представления, снова вызвав делегат приложения.