0

我有一个 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 连接到按钮。但是每次我点击这个按钮时,我都会得到一个空指针异常,因为 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] 中,我都初始化了那些 UIViewcontrollers 并将它们的视图作为 subView 添加到 MainViewController。

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

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

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

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

1 回答 1

5

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

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

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

1.

这太疯狂了。如果你想UICollectionViewCell从一个 xib 加载你的子类,你不这样做,你可以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”。ACGSize是一个带有 awidth和的 C 结构体height。你可以用CGSizeMake(<width>,<height>). 你会让你的 init 方法看起来像这样:

- (id)initWithSize:(CGSize)size

但是你真的不想UIViewControllerCGSize...

4

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

5

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

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

于 2013-03-15T15:04:06.450 回答