【问题标题】:UICollectionViewCell's are not retaining with ARCUICollectionViewCell 不与 ARC 一起保留
【发布时间】:2013-03-15 14:12:24
【问题描述】:

我有一个 UICollectionView,它从 web 服务接收数据。根据它收到的数据,它在我的 UICollectionView 上绘制单元格。每个单元格都是一个扩展 UICollectionViewCell 的自定义类。每个 UICollectionViewCell 都是通过 .nib 加载的。我的 init 方法如下所示:

@implementation GridCell

- (id)initWithFrame:(CGRect)frame
{
        if (self)
        {
            // Initialization code
            NSArray *arrayOfViews = [[NSBundle mainBundle] loadNibNamed:@"GridCell" owner:self options:nil];

            if ([arrayOfViews count] < 1) {
                return nil;
            }

            if (![[arrayOfViews objectAtIndex:0] isKindOfClass:[UICollectionViewCell class]]) {
                return nil;
            }

            self = [arrayOfViews objectAtIndex:0];


            // It is important that you set the properties of the view after the above assignment
            // because self is assigned to the nib after that call.
            self.layer.masksToBounds = NO;
            self.layer.shadowColor = [[UIColor blackColor] CGColor];
            self.layer.shadowOffset = CGSizeMake(0.0, 1.0);
            self.layer.shadowOpacity = 0.17;
            self.layer.shadowRadius = 0.35f;
            self.layer.shouldRasterize = YES;


        }

    return self;
}

我有一个基本上是 UIViewController 的 GridViewController :

@implementation GridViewController

- (id)initWithSize:(CGFloat)frameWidth :(CGFloat)frameHeight {

    self = [super init];
    if(self) {

        // Have the getGridView returning the initialized view
        // then assign it to the GridViewControllers view property
        self.view = [self getGridView:frameWidth:frameHeight];

    }
    return self;
}

-(UIView *)getGridView:(CGFloat)width :(CGFloat)height {


    UIView *gridHolder = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)];

    UICollectionViewFlowLayout *flow = [[UICollectionViewFlowLayout alloc]init];
    [flow setScrollDirection:UICollectionViewScrollDirectionHorizontal];

    CGRect screen = [[UIScreen mainScreen] bounds];
    CGFloat screenheight = screen.size.height;

    // It is an iphone 5, setup the cellsize and the spacing between cells.
    if(screenheight > 480) {


        [flow setItemSize:CGSizeMake( (gridHolder.frame.size.width / 1.85) , (gridHolder.frame.size.height / 3.25) )];
        [flow setSectionInset:UIEdgeInsetsMake(0, 0, 0, 0)];
        [flow setMinimumInteritemSpacing:0];
        [flow setMinimumLineSpacing:10];


    // It is an iphone 4, setup the cellsize and the spacing between cells.
    } else {

        [flow setItemSize:CGSizeMake( (gridHolder.frame.size.width / 2.5)  , (gridHolder.frame.size.height / 3.1) - 10)];
        [flow setSectionInset:UIEdgeInsetsMake(0, 0, 0, 0)];
        [flow setMinimumInteritemSpacing:0];
        [flow setMinimumLineSpacing:10];
    }


    self.grid = [[UICollectionView alloc] initWithFrame:CGRectMake(0, 0, gridHolder.frame.size.width, gridHolder.frame.size.height) collectionViewLayout:flow];


    [_grid setBackgroundColor:[UIColor colorWithRed:0.961 green:0.961 blue:0.961 alpha:1]];

    [_grid setDataSource:self];
    [_grid setDelegate:self];
    [_grid setBounces:NO];
    [_grid registerClass:[GridCell class] forCellWithReuseIdentifier:Cell];


    [gridHolder addSubview:self.grid];


    return gridHolder;
}

这个 UIViewController 也是我的 UICollectionViewDataSource。所以我有以下方法:

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

    return [releases count];

}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(10, 10, 10, 10);

}

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    GridCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:Cell forIndexPath:indexPath];

    return cell; // <-- finally return the cell


}

我在单元格上添加了一个 UIButton。我将 IBAction 连接到按钮。但是每次我点击这个按钮时,我都会得到一个空指针异常,因为 GridIcon 已经被 ARC 丢弃了。我必须在某处保留 GridIcon 吗?或者克服这个(简单?)问题的最佳做法是什么?

我的 GridIcon.m 中的方法是:

- (IBAction)cellClicked {
    NSLog(@"test");
}

我的 GridIcon.h 文件有一个 IBAction 描述:

@interface GridCell : UICollectionViewCell
- (IBAction)cellClicked;
@end

编辑:

jackslash,感谢您花时间和精力让我意识到这个非常疯狂的结构。让我解释一下我是如何设置这个项目的。

我有一个 MainViewController,我在 AppDelegate.m 中将它设置为 RootViewController。然后在我的 MainViewController 中我初始化 2 UIVIewController。其中之一是我的 GridViewController,它设置 UICollectionView。

所以这个 UICollectionView 的数据源是我初始化的 UIViewController。我需要为此 UIViewController 绘制屏幕区域,因此我将另一个 UIViewController 的高度提供给 GridViewController。而getGridView方法得到的是屏幕高度减去其他UIViewConroller的视图的高度。

结构是这样的:

@interface MainViewController: UIViewController
// These next two classes both extend UIViewController
@property(nonatomic, strong) GridViewController *gridViewcontroller;
@property(nonatomic, strong) BottomBarController *bottomBarcontroller;
@end

在我的 MainViewController.m [viewDidLoad] 中,我都初始化了那些 UIViewcontroller 并将它们的视图作为子视图添加到 MainViewController。

那么最好的方法是什么?我应该将 UICollectionViewController 与我的 GridViewController 分开吗?但是这个 UICollectionView 是如何知道要在屏幕的哪个区域绘制的呢?

对于我的 GridCell 中的 init 方法,我实际上使用它在我的 GridCell 下方绘制阴影。如果没有这个 init 方法,我将如何在我的单元格下实现绘图?

编辑 2: 除了我上面的编辑:

  • 我在每个 GridCell 上都有一个 UIImageView 和一个 UILabel。我将如何针对我的代码中的那些?

【问题讨论】:

    标签: ios objective-c


    【解决方案1】:

    所以这里发生的事情在很多方面都搞砸了。

    1. 您的 GridCell 初始化方法是心理的
    2. 您留下了一些未命名的 Objective-c 方法参数(格式错误)
    3. 您有一个方法 - (id)initWithSize:(CGFloat)frameWidth :(CGFloat)frameHeight ,希望从名称中获取 CGSize,但它需要两个浮点数
    4. 由于某种原因,您正在使用 -(id)initWithSize:: 方法来初始化您的视图控制器
    5. 您的 GridCell 类文件的名称与其包含的类不同(格式错误)

    您似乎从根本上误解了这一切应该如何运作。我将在这里为您提供帮助,但请记住,您应该花时间了解这里的所有内容,并阅读更多有关 iOS 的信息。不妨看看 iTunes U (CS193p) 上的 iOS 课程,它是免费的,可以帮助您编写更好的代码。

    1.

    这太疯狂了。如果您想从 xib 加载您的 UICollectionViewCell 子类,您不这样做,您可以在 UICollectionViewController 子类中使用集合视图注册 nib,如下所示:

    UINib * cellNib = [UINib nibWithNibName:@"GridCell" bundle:[NSBundle mainBundle]];
    [self.collectionView registerNib:cellNib forCellWithReuseIdentifier:cellReuseIdentifier];
    

    然后,当您进入单元格时,会从 xib 文件中为您加载单元格

    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
    

    确保将GridCell.xib 文件中的单元格类设置为GridCell 子类。永远不要再写这样的 init 方法了。

    2.

    -(UIView *)getGridView:(CGFloat)width :(CGFloat)height
    

    始终在 Objective-c 方法签名中命名所有参数。

    -(UIView *)getGridViewWithWidth:(CGFloat)width andHeight:(CGFloat)height
    

    是英里和英里更好。但是您可能会更好地使用CGSize...

    3

    - (id)initWithSize:(CGFloat)frameWidth :(CGFloat)frameHeight
    

    在 Objective-c 中,我们希望它采用 CGSize 参数,因为您的方法名为“initWithSize”。 CGSize 是具有 widthheight 的 C 结构。您可以使用CGSizeMake(&lt;width&gt;,&lt;height&gt;) 制作一个。你会让你的 init 方法看起来像这样:

    - (id)initWithSize:(CGSize)size
    

    但您并不想用CGSize 初始化UIViewController...

    4

    UIViewController 没有任何类型的 init 方法来接受任何类型的大小或维度是有原因的。视图控制器的想法是,它的视图大小由其父(或窗口)设置,然后负责在其视图中绘制其内容,无论大小。作为UIViewController 的子类在UIKit 中,有一个地方可以加载其他视图和视图控制器,这些视图和视图控制器需要显示您应该显示的任何内容。查看方法-(void)viewDidLoad 并覆盖它。但即便如此,如果您只是将 UICollectionViewController 子类化,您的情况会好得多,因为您不需要任何类型的容器,并且您的视图控制器的视图属性已经是一个 collectionView 以及许多其他好处。

    5

    GridIcon.hGridIcon.m 文件重命名为它们包含的类的名称。始终遵循此规则,以确保您未来的理智,即使不是为您项目工作的其他所有人。

    最后,它崩溃的原因不是因为 ARC 或其他技术故障,而是因为这里的实现存在真正的基本问题。

    【讨论】:

    • jackslash,在我原来的帖子下面提出更多问题。你能回答这些问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-29
    • 2011-12-07
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多