Доступ к переменным через делегирование

#iphone #objective-c

#iPhone #objective-c

Вопрос:

Я столкнулся с ситуацией в Objective-C, когда я пытаюсь получить доступ к переменной объекта через другой объект. Классы (упрощенный):

A.h

 @interface A : NSObject {  
  NSMutableArray *someStuff;  
}  

@property (nonatomic, retain) NSMutableArray *someStuff;    

@end 
  

A.m

 @implementation A  

@synthesize someStuff;  

//  blah, blah, blah  
  

Затем, поскольку я создаю приложение для iPhone, есть делегат приложения, который содержит переменную этого типа объекта:

AppDelegate.h

 @interface AppDelegate : NSObject <UIApplicationDelegate> {  

   A *aPtr;  
}  

@property (nonatomic, retain) A *aPtr;  
@end  
  

AppDelegate.m

 @implementation AppDelegate  

@synthesize aPtr;  
// blah, blah, blah  
  

Затем, в другом классе (в этом контроллере представления), я пытаюсь получить доступ к ‘someStuff’ таким образом:

AViewController.m

 AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];  

NSMutableArray *someArray = appDelegate.aPtr.someStuff;  
  

Итак, проблема в том, что это прекрасно работает. Я думаю, что я слишком большой любитель Java, чтобы понять, почему это не сработает. Кто-нибудь может просветить меня?

Большое спасибо,

Крейг

Ответ №1:

Вам нужно инициализировать это таким образом

 AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];  

NSMutableArray *someArray = appDelegate.someArray;
  

Это решит вашу проблему…..

Комментарии:

1. неправильно, приведение не требуется, приведенный выше код не должен прерываться (и не прерывается — просто проверил это)

2. Хорошо, я попробовал это. Компилятор жалуется, что someStuff не является объектом в AppDelegate (которым он, конечно, не является). Ошибка компилятора, которую я обычно получаю, заключается в том, что someStuff не является объектом A. Все еще застрял.

3. Итак, у вас ошибка компилятора, а не ошибка времени выполнения? Вы должны были указать это. Убедитесь, что у вас есть все включаемые на месте, чтобы компилятор знал, какие атрибуты какому классу принадлежат, и что у вас нет более одной версии класса A, которую вы могли бы включить, одна без someStuff .

4. Я думаю, вы, должно быть, импортируете свой делегат в классе .m и не объявляете класс своего делегата в классе .h. Объявите свой делегат в .h как @Class yourdelegate и импортируйте его в класс .m.

Ответ №2:

Крейг,

appDelegate.aPtr вернется null . поскольку он еще не инициализирован, и когда вы пытаетесь получить доступ к какому-либо члену null объекта (в Java NULLPointerException ).Его поведение соответствует ожиданиям.(это прекрасно работает).

Спасибо,

Ответ №3:

Равин прав. Определение класса определяет IVAR и свойства для класса, поэтому вы определили iVar, aPtr который ссылается на объект типа A . Однако вы не выделили и не инициализировали этот объект.

Примером использования инициализации по умолчанию может быть `aPtr = [[A alloc] init]’.

Комментарии:

1. Извините, я должен был указать, что я инициализировал aPtr. Ваш ответ правильный, учитывая, что я этого не упоминал. Но он инициализирован, так что есть еще кое-что, чего мне не хватает.

2. Это нормально, но принятый вами ответ на самом деле не решает вашу проблему. 1) Приведение не требуется, 2) Вы не объявили iVar / property someArray и 3) он не перешел на следующий уровень косвенности, который вы сделали в коде, который вы опубликовали, чтобы перейти к aPtr.someStuff . Пока вы счастливы, рад, что у вас все работает.

Ответ №4:

Все это звучит подозрительно, поскольку в ObjC вам разрешено отправлять сообщения в ноль без проблем, а свойства — это просто оцифрованные методы. Например, вы можете

 view = nil;
view.hidden = NO;
  

и это не взрывается, это просто ничего не делает.

Итак, поскольку AppDelegate.aPtr.someStuff просто

 [[appDelegate aPtr] someStuff];
  

и [AppDelegate aPtr] ничего не делает и возвращает nil, поэтому должно быть безопасно вызывать [[AppDelegate aPtr] someStuff] без проблем, но и без каких-либо результатов.

Итак, хотя это проблема с использованием объектов, которые не были инициализированы (что чаще всего следует делать в назначенном конструкторе соответствующего объекта), поскольку вы не получаете ожидаемых результатов, в моем понимании «отправки сообщения на ноль» в ObjC это не должно привести к сбою. Если это так, то либо я упускаю суть, либо проблема вызвана чем-то другим, а не этим вызовом.

Редактировать

только что проверено: если вообще не инициализировано, все работает, как я объяснил: ObjC разрешает отправлять сообщения с нулевым значением:

 A *aPtr = appDelegate.aPtr;
NSMutableArray *someArray = aPtr.someStuff;
NSLog(@"%@", someArray);
  

или

 NSMutableArray *someArray = appDelegate.aPtr.someStuff;
NSLog(@"%@", someArray);
  

оба не прерываются и не выводят null.

Если вы правильно инициализируете A, но не инициализируете someStuff в A, он все равно не прерывается, но выводит null. Проблема может заключаться в том, что вы инициализируете aPtr для класса, отличного от A, и в этом случае вы получаете нераспознанное исключение селектора (вы должны быть в состоянии увидеть его в журнале ошибок) и сбой программы.