UICollectionViewCell不保留ARC

时间:2013-03-15 14:12:25

标签: ios objective-c

我有一个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;
}

我有一个GridViewController,它基本上是一个UIViewController:

@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连接到按钮。但每次我点击这个按钮,我都会得到一个nullpointer异常,因为ARC已经抛弃了GridIcon。我必须在某个地方保留GridIcon吗?或者,克服这个(简单?)问题的最佳做法是什么?

驻留在我的GridIcon.m中的方法是:

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

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

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

修改:

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

我有一个MainViewController,我在AppDelegate.m中设置为RootViewController。然后在我的MainViewController中使用init 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]中,我都启动了那些UIView控制器,并将它们的视图作为子视图添加到MainViewController。

那么实现这一目标的最佳方法是什么?我应该将UICollectionViewController与我的GridViewController分开吗?但是,这个UICollectionView如何知道要在哪个屏幕区域上绘制?

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

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

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

1 个答案:

答案 0 :(得分:5)

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

  1. 您的GridCell init方法是精神
  2. 您留下了一些未命名的Objective-c方法参数(错误形式)
  3. 你有一个方法- (id)initWithSize:(CGFloat)frameWidth :(CGFloat)frameHeight,人们希望从名称中取CGSize但它需要两个花车
  4. 出于某种原因,您使用-(id)initWithSize::方法初始化视图控制器
  5. 您的GridCell类文件与其包含的类名称不同(错误格式)
  6. 你似乎从根本上误解了这一切是如何起作用的。我会在这里帮助你,但请记住,你应该花时间去理解这里的一切,并且还要去阅读更多关于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(<width>,<height>)创建一个。你可以让你的init方法看起来像这样:

    - (id)initWithSize:(CGSize)size
    

    但你真的不想用UIViewController来发起CGSize ...

    4

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

    5

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

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