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'. TheviolinMaker`объект содержит все необходимые данные.

Я думаю, что вы делаете это более сложным, чем это должно быть. Все, что вам нужно, это (A) класс, который инкапсулирует данные для каждой записи, извлеченной из вашего SQL. В этом случае похоже, что ViolinMaker делает это. (B) Вам нужен массив (или другая коллекция) в делегате приложения для хранения нескольких экземпляров ViolinMaker. (C) Вам нужен код в каждом viewcontroller, который будет обращаться к массиву / коллекции в делегате приложения, чтобы viewcontroller мог выбирать необходимые ему экземпляры ViolinMaker.

Edit02:

Нет, я не могу использовать эти 3 строки, поскольку objectAtIndex:indexPath.row доступен только внутри функции didSelectRow. Что означает, что мне придется реконструировать таблицу и все ее данные.

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

Чтобы заполнить таблицу, вам нужно извлечь некоторые значения в виде массива. Скорее всего, вы бы взяли ключи, которые являются именами скрипачей. Затем вы сортируете массив по алфавиту, а затем заполняете каждую строку значением массива со значением index.row.

Аналогичным образом, если вам нужно добавить данные в одном представлении, вы можете записать в violinMakersDict а затем получить доступ к этим данным из другого представления, снова вызвав делегат приложения.

Другие вопросы по тегам