[iphone] Interface Builder로 작성된 nib 파일을 사용하여 UIView를로드하는 방법

조금 정교한 작업을 시도하고 있지만 가능한 일을하려고합니다. 그래서 여기에 모든 전문가에게 도전이 있습니다 (이 포럼은 많은 사람들이 모여 있습니다 :)).

설문지 “구성 요소”를 작성하고 있는데 NavigationContoller(my QuestionManagerViewController) 에로드하려고합니다 . “컴포넌트”는 “빈”UIViewController , 답변이 필요한 질문에 따라 다른보기를로드 할 수 있습니다.

내가하는 방식은 다음과 같습니다.

  1. Question1View 객체를 UIView서브 클래스 로 생성하여IBOutlets .
  2. (인터페이스 빌더를 사용하여) Question1View.xib (내 문제는 어디에 있습니까? )를 작성하십시오. UIViewControllerand UIView클래스를 Question1View 클래스로 설정했습니다 .
  3. 출구를 뷰의 구성 요소와 연결합니다 (IB 사용).
  4. 나는 우선 initWithNib내의를 QuestionManagerViewController같이하기 :

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

코드를 실행할 때 다음 오류가 발생합니다.

2009-05-14 15 : 05 : 37.152 iMobiDines [17148 : 20b] *** 발견되지 않은 예외 ‘ NSInternalInconsistencyException‘(으) 로 인해 앱을 종료하는 이유 : ‘ -[UIViewController _loadViewFromNibNamed:bundle:]“Question1View”펜촉이로드되었지만 뷰 콘센트가 설정되지 않았습니다.’

viewController 클래스를 만들 필요없이 nib 파일을 사용하여 뷰를로드하는 방법이 있다고 확신합니다.



답변

펜촉을 배열로 처리하는 대신보기에 액세스하는 더 쉬운 방법도 있습니다.

1 ) 나중에 액세스하려는 콘센트가있는 사용자 정의 View 서브 클래스를 작성하십시오. –MyView

2 ) nib를로드하고 처리하려는 UIViewController에서로드 된 nib의 뷰를 보유 할 IBOutlet 특성을 작성하십시오 (예 :

MyViewController (UIViewController 서브 클래스)

  @property (nonatomic, retain) IBOutlet UIView *myViewFromNib;

(합성하여 .m 파일로 릴리스하는 것을 잊지 마십시오)

3) IB에서 펜촉을 열고 ( ‘myViewNib.xib’라고 함) 파일 소유자를 MyViewController로 설정하십시오.

4) 이제 파일의 소유자 콘센트 myViewFromNib를 펜촉의 기본보기에 연결하십시오.

5) 이제 MyViewController에서 다음 줄을 작성하십시오.

[[NSBundle mainBundle] loadNibNamed:@"myViewNib" owner:self options:nil];

이제 속성을 “self.myViewFromNib”로 호출하면 펜촉에서 뷰에 액세스 할 수 있습니다!


답변

다들 감사 해요. 나는 내가 원하는 것을 할 수있는 방법을 찾았다.

  1. 당신 UIView과 함께 당신 을 만드십시오 IBOutlet.
  2. IB에서 xib를 작성하여 원하는대로 디자인하고 다음과 같이 링크하십시오 UIViewController. 파일 소유자의보기가 기본보기에 연결되고 해당 클래스가 1) 단계에서 선언됩니다.
  3. 컨트롤을 IBOutlets 와 연결하십시오 .
  4. DynamicViewController부하 / XIB를 볼 것을 결정하는 그 논리를 실행할 수 있습니다. 그것이 결정을 내리면, loadView방법에 다음과 같이 넣으십시오 :

    NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"QPickOneView"
                                                      owner:self
                                                    options:nil];
    
    QPickOneView* myView = [ nibViews objectAtIndex: 1];
    
    myView.question = question;

그게 다야!

메인 번들의 loadNibNamed메소드는 뷰를 초기화하고 연결을 생성합니다.

이제 ViewController는 메모리의 데이터에 따라 뷰 또는 다른 뷰를 표시 할 수 있으며 “부모”화면은이 논리를 신경 쓸 필요가 없습니다.


답변

답변 중 일부에 대해 잘 모르겠지만 다음에 Google에서 검색 할 때이 답변을 입력해야합니다. 키워드 : “nib에서 UIView를로드하는 방법”또는 “NSBundle에서 UIView를로드하는 방법”

다음은 Apress Beginning iPhone 3 책 (247 페이지의 “새 테이블 뷰 셀 사용”) 에서 거의 100 % 완성 된 코드입니다 .

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:@"Blah"
                                                 owner:self options:nil];
    Blah *blah;
    for (id object in bundle) {
        if ([object isKindOfClass:[Blah class]]) {
            blah = (Blah *)object;
            break;
        }
    }
    assert(blah != nil && "blah can't be nil");
    [self.view addSubview: blah];
} 

이것은 클래스가로 설정된 것을 포함하는 nib라는 UIView서브 클래스 가 있다고 가정합니다 .BlahBlahUIViewBlah


카테고리 : NSObject + LoadFromNib

#import "NSObject+LoadFromNib.h"

@implementation NSObject (LoadFromNib)

+ (id)loadFromNib:(NSString *)name classToLoad:(Class)classToLoad {
    NSArray *bundle = [[NSBundle mainBundle] loadNibNamed:name owner:self options:nil];
    for (id object in bundle) {
        if ([object isKindOfClass:classToLoad]) {
            return object;
        }
    }
    return nil;
}

@end

스위프트 확장

extension UIView {
    class func loadFromNib<T>(withName nibName: String) -> T? {
        let nib  = UINib.init(nibName: nibName, bundle: nil)
        let nibObjects = nib.instantiate(withOwner: nil, options: nil)
        for object in nibObjects {
            if let result = object as? T {
                return result
            }
        }
        return nil
    }
}

그리고 사용중인 예 :

class SomeView: UIView {
    class func loadFromNib() -> SomeView? {
        return self.loadFromNib(withName: "SomeView")
    }
}


답변

하나 이상의 Outlet Collection 인 사용자 정의보기 인스턴스를 관리 해야하는 모든 사람들을 위해 다음 과 같이 @Gonso, @AVeryDev 및 @Olie 답변을 병합하고 사용자 정의했습니다.

  1. 사용자 정의를 작성 하고 원하는 XIB 에서 루트의 MyView : UIView사용자 정의 클래스 ” 로 설정하십시오 .
    UIView커스텀 클래스

  2. 필요한 모든 아울렛 을 작성하십시오 MyView(지금 지점 3 이후 IB가 UIViewController원하는대로 아울렛을 사용자 정의보기가 아닌 아울렛에 연결하도록 제안하기 때문에 지금 수행하십시오 ).
    커스텀 클래스 아울렛

  3. 사용자 정의보기 XIB UIViewController파일 소유자 ” 로 설정하십시오 .
    여기에 이미지 설명을 입력하십시오

  4. 에서 UIViewController새로운 추가 UIViews의 각 인스턴스에 대해 MyView당신이 원하는, 그리고에 연결 UIViewController만드는 아울렛 컬렉션 : 이러한 뷰는 사용자 정의보기 인스턴스에 대해 “래퍼”뷰 역할을합니다;
    여기에 이미지 설명을 입력하십시오

  5. 마지막에 viewDidLoad당신의 UIViewController추가 다음 줄 :

NSArray *bundleObjects;
MyView *currView;
NSMutableArray *myViews = [NSMutableArray arrayWithCapacity:myWrapperViews.count];
for (UIView *currWrapperView in myWrapperViews) {
    bundleObjects = [[NSBundle mainBundle] loadNibNamed:@"MyView" owner:self options:nil];
    for (id object in bundleObjects) {
        if ([object isKindOfClass:[MyView class]]){
            currView = (MyView *)object;
            break;
        }
    }

    [currView.myLabel setText:@"myText"];
    [currView.myButton setTitle:@"myTitle" forState:UIControlStateNormal];
    //...

    [currWrapperView addSubview:currView];
    [myViews addObject:currView];
}
//self.myViews = myViews; if need to access them later..

답변

재사용 할 사용자 정의 UIView를 인스턴스화하기 위해 UINib를 사용합니다.

UINib *customNib = [UINib nibWithNibName:@"MyCustomView" bundle:nil];
MyCustomViewClass *customView = [[customNib instantiateWithOwner:self options:nil] objectAtIndex:0];
[self.view addSubview:customView];

이 경우 필요한 파일은 MyCustomView.xib , MyCustomViewClass.hMyCustomViewClass.m
입니다 [UINib instantiateWithOwner]. 배열 을 반환하는 참고 이므로 재사용하려는 UIView를 반영하는 요소를 사용해야합니다. 이 경우 첫 번째 요소입니다.


답변

UIViewInterface Builder에서 뷰 컨트롤러의 클래스를 하위 클래스로 설정해서는 안됩니다 . 그것은 가장 확실하게 문제의 일부입니다. UIViewController하위 클래스 또는 사용자 정의 클래스 로 남겨 두십시오 .

XIB에서 유일한보기를로드에 관해서는, 나는 당신이 있다는 가정하에 있었다 있었다 (이 확장되지 않는 경우에도 뷰 컨트롤러의 일종 가지고 UIViewController인터페이스에서 파일의 소유자로 설정을 사용자의 요구에 너무 무겁 수 있습니다) 인터페이스를 정의하기 위해 사용하려는 경우 빌더. 나는 이것을 확인하기 위해 약간의 연구를했다. 그렇지 않으면의 인터페이스 요소에 액세스 할 UIView수있는 방법이 없거나 이벤트에 의해 코드의 고유 한 메소드를 트리거 할 수있는 방법이 없기 때문입니다.

UIViewController뷰의 파일 소유자로 a를 사용하면 뷰 initWithNibName:bundle:를로드하고 뷰 컨트롤러 객체를 다시 가져올 수 있습니다. IB view에서 xib의 인터페이스가있는 콘센트를보기로 설정하십시오. 파일 소유자로 다른 유형의 객체를 사용하는 경우 NSBundleloadNibNamed:owner:options:메소드를 사용하여 펜촉을로드하고 파일 소유자의 인스턴스를 메소드에 전달해야합니다. IB에서 정의한 콘센트에 따라 모든 속성이 올바르게 설정됩니다.


답변

loadNibNamed 대신 UIViewController의 initWithNibName을 사용할 수도 있습니다. 더 간단합니다.

UIViewController *aViewController = [[UIViewController alloc] initWithNibName:@"MySubView" bundle:nil];
[self.subview addSubview:aViewController.view];
[aViewController release];  // release the VC

이제 MySubView.xib 및 MySubView.h / m을 작성하면됩니다. MySubView.xib에서 File ‘s Owner 클래스를 UIViewController로 설정하고 클래스를 MySubView로 설정하십시오.

subview부모 xib 파일을 사용하여 크기와 위치를 지정할 수 있습니다 .