Programming

UITableViewCell 서브 클래스로 "-layoutSubviews를 실행 한 후에도 자동 레이아웃이 여전히 필요합니다"

procodes 2020. 7. 21. 21:59
반응형

UITableViewCell 서브 클래스로 "-layoutSubviews를 실행 한 후에도 자동 레이아웃이 여전히 필요합니다"


XCode 4.5와 iOS 6을 사용하여 사용자 정의 셀이있는 간단한 테이블보기가있는 앱을 개발 중입니다. iOS 5 이하에서 100 번이 작업을 수행했지만 어떤 이유로 새로운 autoLayout 시스템으로 인해 많은 문제가 발생합니다.

IB에서 테이블 뷰와 프로토 타입 셀을 설정하고 하위 뷰를 추가하고이를 IBOutlets로 연결 한 다음 대리인과 데이터 소스를 설정했습니다. 그러나 이제 첫 번째 셀을에서 가져올 때마다 cellForRowAtIndexPath다음 오류가 발생합니다.

***-[ShopCell layoutSublayersOfLayer :]의 어설 션 실패, /SourceCache/UIKit_Sim/UIKit-2372/UIView.m:5776

*** catch되지 않은 예외 'NSInternalInconsistencyException'으로 인해 앱을 종료하는 이유 : '-layoutSubviews를 실행 한 후에도 자동 레이아웃이 여전히 필요합니다. ShopCell의 -layoutSubviews 구현은 super를 호출해야합니다. '

서브 클래스 셀 (ShopCell)에서 -layoutSubviews 메소드를 구현하지 않았으며, 그렇게하려고하고 슈퍼 호출을 추가하려고해도 여전히 동일한 오류가 발생한다고 제안합니다. IB의 셀에서 하위 뷰를 제거하고 표준 UITableViewCell로 변경하면 모든 것이 예상대로 작동하지만 물론 셀에 데이터가 없습니다.

나는 내가 놓친 간단한 것이 있다고 확신하지만, 내가 잘못한 것을 제안하는 문서 나 안내서를 찾을 수 없습니다. 도움을 주시면 감사하겠습니다.

편집 : IB에서 UITableViewCell로 변경하고 모든 하위 뷰를 그대로 두려고 시도했지만 여전히 동일한 오류가 발생했습니다.


코드에 제약 조건을 수동으로 추가하는 동안 동일한 문제가 발생했습니다. 코드에서 다음을 수행했습니다.

{
    [self setTranslatesAutoresizingMaskIntoConstraints:YES];
    [self addSubview:someView];
    [self addSubview:someOtherView];
    [self addConstraint:...];
}

가설

내가 알 수있는 문제는을 비활성화 translatesAutoresizingMaskIntoConstraints하면 UITableViewCell이 자동 레이아웃을 사용하기 시작하고 기본 구현이 layoutSublayersForLayersuper를 호출하지 않기 때문에 자연스럽게 실패한다는 것입니다 . 호퍼 또는 다른 도구를 가진 사람이이를 확인할 수 있습니다. IB를 사용하고 있기 때문에 이것이 왜 문제인지 궁금 할 것입니다 ... 그리고 IB를 사용하면 translatesAutoresizingMaskIntoConstraints제약 조건을 추가하는 뷰에 대해 자동으로 비활성화 됩니다 (너비와 높이 제약 조건이 자동으로 추가됩니다).

해결책

내 해결책은 모든 것을로 옮기는 것이 었습니다 contentView.

{
   [self.contentView addSubview:someView];
   [self.contentView addSubview:someOtherView];
   [self.contentView addConstraint:...];
}

인터페이스 빌더에서 작동하는지 100 % 확신 할 수는 없지만 셀에 모든 것을 밀어 넣으면 (직접 무언가가 있다고 가정) 작동합니다. 이것이 당신에게 도움이되기를 바랍니다!


분명히 UITableViewCell의 layoutSubviews 구현은 super를 호출하지 않으므로 자동 레이아웃의 문제입니다. 아래 카테고리를 프로젝트에 드롭하면 문제가 해결되는지 궁금합니다. 테스트 프로젝트에 도움이되었습니다.

#import <objc/runtime.h>
#import <objc/message.h>

@implementation UITableViewCell (FixUITableViewCellAutolayoutIHope)

+ (void)load
{
    Method existing = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method new = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existing, new);
}

- (void)_autolayout_replacementLayoutSubviews
{
    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];
}

@end

테이블 셀에서 backgroundView를 사용할 때 셀에 하위 뷰로 추가되므로 대부분의 하위 뷰가 테이블 셀의 contentView에 추가되어야하므로 일반적으로 더 잘 작동해야합니다.

참고 : 이 버그는 iOS7에서 수정 된 것으로 보입니다. 이 코드를 제거하거나 적어도 런타임 검사를 추가하여 iOS6에서 실행되는 경우에만 수행되도록 할 수있었습니다.


몇 달 동안 같은 버그가있었습니다. 그러나 나는 무엇이 문제인지 발견했다.

IB 파일을 만들면 a UIView가 이미 추가되었습니다. 이보기를 사용하면 자동 레이아웃이 비활성화 되어도 앱이 충돌하지 않습니다 (그러나 다른 문제가 있음). 자동 레이아웃을 사용 하는 경우 객체 라이브러리에서 올바른를 선택해야합니다 UITableViewCell.

사실, 당신은해야한다 항상 모든 파단이 추가되기 때문에이 항목을 사용하여 contentViewUITableViewCell.

그게 다야. 모두 괜찮을 것입니다.


나는 custom UITableViewHeaderFooterView+ xib 와 같은 문제가있었습니다 .

여기에 몇 가지 답변이 있지만 -layoutSubviews내 맞춤 바닥 글보기 클래스에서 어떤 구현 이 문제를 해결 하는지 발견 했습니다.

-(void)layoutSubviews
{
    [super layoutSubviews];
    [self layoutIfNeeded]; // this line is key
}

layoutSubviews 구현에서 제약 조건을 수정 한 결과로 이것을 보았습니다. 메소드의 처음에서 끝으로 호출을 super로 이동하면 문제가 해결되었습니다.


iOS 7에서 동일한 문제가 발생했습니다 (iOS 8이 수정 된 것으로 보입니다). 나를위한 해결책 [self.view layoutIfNeeded]은 내 viewDidLayoutSubviews방법 이 끝날 때 전화하는 것이 었습니다 .


나는 같은 문제가 있었다. 문제는 셀 Xib를 만드는 방식에 있습니다. 나는 보통과 같은 Xib를 만들고 기본 "UIView"의 유형을 내 사용자 정의 UITableViewCell 클래스로 변경했습니다. 올바른 방법은 먼저 기본 뷰를 삭제 한 다음 테이블 뷰 셀 객체를 xib로 드래그하는 것입니다. 자세한 내용은 여기 : http://allplayers.github.io/blog/2012/11/18/Custom-UITableViewCell-With-NIB/


사용자 정의 테이블 뷰 셀의 모든 하위 뷰에 대해 "자동 레이아웃"을 해제하여 문제를 해결했습니다.

사용자 정의 셀의 xib에서 서브 뷰를 선택하고 파일 관리자> 인터페이스 빌더 문서> 자동 레이아웃 사용을 선택 취소하십시오.


나는 비슷한 문제가 UITableViewCell아니라 UITableView그 자체로 문제가 있었다 . Google의 첫 번째 결과이므로 여기에 게시하겠습니다. 그게 viewForHeaderInSection문제 라는 것이 밝혀졌습니다 . 나는를 만들고로 UITableViewHeaderFooterView설정 translatesAutoresizingMaskIntoConstraints했다 NO. 이제 흥미로운 부분이 있습니다.

IOS 7:

// don't do this on iOS 7
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

이 작업을 수행하면 앱이 충돌합니다.

-layoutSubviews를 실행 한 후에도 자동 레이아웃이 계속 필요합니다. UITableView의 -layoutSubviews 구현은 super를 호출해야합니다.

좋아, 자동 뷰를 테이블 뷰 헤더와 하위 뷰에서만 사용할 수 있다고 생각했습니다. 그러나 나중에 볼 때 그것은 진실이 아닙니다. 요약하면 : iOS 7에서 헤더의 자동 크기 조정 마스크를 비활성화하지 마십시오. 그렇지 않으면 정상적으로 작동합니다.

iOS 8 :

// you have to do this, otherwise you get an auto layout error
sectionHeader.translatesAutoresizingMaskIntoConstraints = NO;

이것을 사용하지 않으면 다음과 같은 결과가 나옵니다.

Unable to simultaneously satisfy constraints.

For iOS 8 you have to disable auto resizing mask for the header.

Don't know why it behaves in this way but it seems that Apple did fix some things in iOS 8 and auto layout is working differently on iOS 7 and iOS 8.


As someone above has already stated, when you create a view for use in a UITableView, you have to delete the view created by default and drag a UITableViewCell or UITableViewHeaderFooterView as the root view. However, there is a way to fix the XIB in case you had missed that part. You have to open the XIB file in a text editor and in the root tag and its direct child add/change the attribute translatesAutoresizingMaskIntoConstraints to YES, for example

<view contentMode="scaleToFill" horizontalHuggingPriority="1000" id="1" translatesAutoresizingMaskIntoConstraints="YES" customClass="MXWCollapsibleTableHeaderView">


I am encountering this and it seems that it is related to UITableViewCell subclasses as prototype cells that specifically have other custom UIView subclasses added to them. I stress the 'custom' here because I have been successful with cells that just have UIKit children, but it falls over when trying to build the constraints for views I have created bespoke, throwing the error stated in the authors question.

I have had to separate my cells into independent nibs that don't use AutoLayout.

Let's hope Apple clean up this mess.


Add your subviews to the contentView of the cell instead of the cell itself. So instead of:

[self addSubview:someView];

you must use

[self.contentView addSubview:someView];


I encountered this one because I had initially added a UIView instead of a UITableViewCell to a xib file.


I eliminated this error by uncoupling the backgroundView connector from my background UIImageView and accessoryView connector from my UIButton customisations. I suspect that these were not meant to be used the way I was using them.


I had run into this issue first time today. Up until now I had some various experience in using prototype UITableViewCell subclasses but never ran into this issue. What was different about the cell I was working with was that I had an IBOutlet to the -backgroundView which I was using to color the cell. I found that if I created a new property and still added a fresh UIView which stretched the span of the entire cell, this assertion went away. To verify this was the cause, I went back to attaching this view to the backgroundView outlet and the assertion reappeared. So far, no other issues using AutoLayout in a subclassed prototype UITableViewCell since I've made this change.


I didn't get any proper solution for this issue but you can fix it by using frames and not setting translatesAutoresizingMaskIntoConstraints property to No (by default its yes, so don't set it)

CGRect headerViewFrame = CGRectMake(0,0,320,60); //Frame for your header/footer view
UIView *tableHeaderView = [[UIView alloc] initWithFrame:headerViewFrame];
tableHeaderView.translatesAutoresizingMaskIntoConstraints = Yes; //Or don't set it at all
[self.tableView setTableHeaderView:tableHeaderView];

I have been experiencing the same thing. It turned out that if you programmatically add a subview from your ShopCell .xib/storyboard, that uses auto layout, as a subview to another view, that exception might be thrown, depending on how your constraints are configured. My guess is that the constraints created in IB is what creates the troubles when programmatically adding a view as a subview, since it's then maintaing constraints from viewA --> viewB meanwhile you might add viewB as a subview of viewC. You got it (that sentence is even confusing myself)?

In my situation - since it was very simple views that caused the problem - I created the views programmatically and not in IB. That solved it. You might extract those views to other xib files and disable auto layout for those. I guess that'd work.


In some situations, this solves the layout problem easily (depending on your layout). Inside you UITableView subclass, in either awakeFromNib or init, set the autoresizing mask:

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

By defaut it is set to UIViewAutoresizingNone


In my case,

The referenced UIImageView for the auto layout for UITableView is assigned to backgroundView of the UITableView.

self.tableView.backgroundView = self.tableBackgroundImageView;

So, I removed UIImageView for backgroundView from the UIView(Root view) and reset(remove) all auto layout reference to that UIImageView. I placed that UIImageView for background at the outside from the UIView(root view). And then assign to the backgroundView of the UITableView in code.

Then fixed.


I have found the solution.

In my case, I created cell's view in storyboard (with auto layout enabled) and I defined the custom UITableViewCell interface in my ViewController.m, I have to move interface to ViewController.h.


I encountered the same problem when I use the storyboard to create the custom UITableViewCell. Fortunately I found the problem, because I outlet the accessoryView([UITableViewCell setAccessoryView:]) to UIButton which I added to the cell.

So it occurred in my project when run on the iOS6.

Solution

I release the outlet between accessoryView and my button which contained the custom cell.

Proposal

You shouldn't used the UITableViewCell's native elements and change it.


This problem can be caused by forgetting to call [super viewDidAppear:] within viewDidAppear, but I'm sure it's not the only cause.


I had exact the same problem. Here is the problem with my project:
When I worked on the Interface Builder to create a custom UITableViewCell, I dragged a View instead of a Table View Cell from the object collection pane in Xcode
as the custom table cell.
If you are in the same situation, here is the solution:
Delete the view in interface builder, make sure you drag a Table View Cell from the object collection pane and redo the custom table cell view. You can copy the objects in the old view and paste them to the canvas for the new Table View Cell.


I had a very similar problem with a table footer view I was setting in Xcode 6, iOS 7+. The solution was in the format of the nib file. Apparently it was stuck in Xcode 4 format or something. Changing the file settings to "opens in: Xcode 6.0" (or Default, for that matter), instantly fixed it. Found the solution by chance: it was driving me crazy, so I deleted the entire file and created again, obviously with the default settings. I have no idea why simply editing the file in the latest Xcode didn't convert it to a Xcode 5+ format, as it usually happens.

f


I went had the same issue. I went to my DetailViewController and renamed the identifier to UIView. It was previously on UITableView. It fixed the problem. This problem doesn't have to be in your DetailViewController. It could be in any other one. Try renaming it to the respected identifier.


I had a similar issue with static table view cells in IB. One of the cells had a subview that had a class that was mistakenly altered to a subclass of UITextfield. The compiler didn't give any warnings/errors. But at runtime the system was unable to load the view controller with the aforementioned crash as a result.


Issue is sequencing of the layout calls to the subviews:

Check out

Shows up in iOS < 8


Solution: change constraints before call super layoutSubviews

- (void)layoutSubviews
{

    [self _updateConstraints];

    [super layoutSubviews];
}

I modified Carl Lindberg's answer to override UITableView instead and it started working for me:

UITableView+AutoLayoutFix.h

@interface UITableView (AutoLayoutFix)
@end

UITableView+AutoLayoutFix.m

#import <objc/runtime.h>

@implementation UITableView (AutoLayoutFix)

+ (void)load
{
    Method existingMethod = class_getInstanceMethod(self, @selector(layoutSubviews));
    Method newMethod = class_getInstanceMethod(self, @selector(_autolayout_replacementLayoutSubviews));

    method_exchangeImplementations(existingMethod, newMethod);
}

- (void)_autolayout_replacementLayoutSubviews
{
    [super layoutSubviews];
    [self _autolayout_replacementLayoutSubviews]; // not recursive due to method swizzling
    [super layoutSubviews];
}

@end

Then in MyViewController.m I just imported the category:

#import "UITableView+AutoLayoutFix.h"

I met the same problem and finally found the reason was that I added one constraint to the UITableViewCell, which should be the UITableViewCell's contentView. When I changed the constraint everything went fine!

참고URL : https://stackoverflow.com/questions/12610783/auto-layout-still-required-after-executing-layoutsubviews-with-uitableviewcel

반응형