Почему этот метод init при загрузке пера возвращает объект из области видимости? - PullRequest
0 голосов
/ 10 февраля 2012

Почему этот метод init возвращает объект вне области видимости?

Используя XCode 4.2, базовый SDK 4.3 и ARC, я пытаюсь загрузить UIView из пера (не UIViewController). Мне не нужно вообще использовать UIViewController в процессе.

После прочтения этого ответа S.O. Вопрос здесь, похоже, это можно сделать: Как загрузить UIView с помощью файла пера, созданного с помощью Interface Builder (Ответ пользователя "MusiGenesis" описывает процесс)

Я создал подкласс UIView с одной меткой:

@interface MyView : UIView
@property (unsafe_unretained, nonatomic) IBOutlet UILabel *textLabel;
@end

В реализации я переопределяю initWithFrame:

- (id)initWithFrame:(CGRect)frame
{
    //self = [super initWithFrame:frame];
    self = [JVUIKitUtils initWithNibName:@"MyView" withOwner:self];
    if( self )
    {
        NSLog(@"Created");
    }
    return self;
}

В И.Б. Я создал файл с именем «MyView.xib» с одним видом. У него есть метка в качестве вложенного представления, и я создал свойство метки, перетащив его в файл h. MyView nib file setup

И в другом файле я создал этот статический метод многократного использования:

+ (id)initWithNibName:(NSString*)nibName withOwner:(id)uiView
{
    id object = nil;
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:uiView options:nil]; // 1 object, out of scope
    for( id tempObject in bundle)
    {
        if( [tempObject isKindOfClass:[uiView class]] ) object = tempObject;
        break;
    }
    return object;
}

Как вы можете видеть на следующем снимке экрана, у пакета есть одна ссылка на объект, но она выходит за рамки.

И отладка: MyView is out of scope

Это мой код для создания экземпляра:

subView = [[MyView alloc] initWithFrame:CGRectZero]; // ok
NSAssert(subView != nil, @"MyView was nil"); // fail

Любые идеи о том, почему другой С.О. плакат смог заставить его работать, но это не так?

Ответы [ 2 ]

3 голосов
/ 10 февраля 2012

Использование владельца кажется немного запутанным при загрузке пера.Похоже, что вы пытаетесь использовать представление как владельца пера и первого объекта в нем.

Пытаетесь ли вы загрузить MyView из вашего пера (т. Е. Является классом представления внутри вашего пера)файлы, определенные как MyView) или вы пытаетесь загрузить подпредставление MyView из пера?

Если представление внутри вашего пера является MyView, вот как его загрузить.Создайте этот статический метод как категорию в UIView:

@implementation UIView (NibLoading)

+ (id)viewWithNibName:(NSString*)nibName
{
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:nil options:nil];
    if ([bundle count])
    {
        UIView *view = [bundle objectAtIndex:0];
        if ([view isKindOfClass:self])
        {
            return view;
        }
        NSLog(@"The object in the nib %@ is a %@, not a %@", nibName, [view class], self);
    }
    return nil;
}

@end

Это позволит вам загрузить любой вид представления из файла пера (представление должно быть первым элементом, определенным в пиру).Вы должны создать свое представление следующим образом:

MyView *view = [MyView viewWithNibName:@"MyView"];

Если представление внутри пера не является MyView, но вы хотите загрузить его как подпредставление MyView, с MyView, определенным как владелец файла в патефайл, сделайте это следующим образом:

@implementation UIView (NibLoading)

- (void)loadContentsFromNibName:(NSString*)nibName
{
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:self options:nil];
    if ([bundle count])
    {
        UIView *view = [bundle objectAtIndex:0];
        if ([view isKindOfClass:[UIView class]])
        {
            //resize view to fit
            view.frame = self.bounds;

            //add as subview
            [self addSubview:view];
        }
        NSLog(@"The object in the nib %@ is a %@, not a UIView", nibName, [view class]);
    }
}

@end

Используя этот подход, просто создайте свое представление как обычно, используя initWithFrame, затем вызовите loadContentsFromNibName, чтобы загрузить содержимое из кончика.Вы бы загрузили свой вид так:

MyView *view = [[MyView alloc] initWithFrame:CGRect(0,0,100,100)];
[view loadContentsFromNibName:@"MyView"];
0 голосов
/ 10 февраля 2012

Ваш [JVUIKitUtils initWithNibName:@"MyView" withOwner:self] подход совершенно неверен. Когда вызывается метод init, объект уже выделяется при вызове [MyView alloc]. Причина, по которой вы объединяете вызовы в метод super init, заключается в том, что эта цепочка будет последовательно соединяться вплоть до метода init NSObject, который просто возвращает экземпляр, которым он является.

Устанавливая «self» в значение (autoreleased) экземпляра, возвращаемое вашим JVUIKitUtils, вы фактически устанавливаете для него адрес памяти, отличный от того, который был выделен при вызове [MyView alloc], что генерирует выход за рамки ошибка.

Вместо этого не создавайте метод init, который вы пытаетесь создать. У вас уже есть метод для создания и инициализации представления на основе пера в вашем методе состояния. Я бы изменил имя и сделал бы что-то вроде:

+ (UIView)newViewWithNibName:(NSString*)nibName withClassType:(Class)uiView
{
    id object = nil;

    // you need some object to assign nib file owner to. use an NSObject.
    NSObject* owner = [[NSObject alloc] init];
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:nibName owner:owner options:nil]; // 1 object, out of scope
    for( id tempObject in bundle)
    {
        if( [tempObject isKindOfClass:] ) object = [tempObject retain];
        break;
    }
    [owner release];
    return object;
}

и затем назовите это как:

MyView* subView = [JVUIKitUtils viewWithNibName:@"MyView" withClassType:[MyView class]];

Я не проверял этот код. Ваш пробег может варьироваться.

...