0

Web サービスからデータを受け取る UICollectionView があります。受け取ったデータに基づいて、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 によって既に破棄されているため、nullpointer 例外が発生します。GridIcon をどこかに保持する必要がありますか? または、この (単純な?) 問題を克服するためのベスト プラクティスは何ですか?

私の GridIcon.m にあるメソッドは次のとおりです。

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

そして、私の GridIcon.h ファイルには IBAction が記述されています:

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

編集 :

ジャックスラッシュ、この本当に狂った構造に気づかせてくれたあなたの時間と努力に感謝します。このプロジェクトのセットアップ方法を説明しましょう。

AppDelegate.m で RootViewController として設定した MainViewController があります。次に、MainViewController で 2 つの UIVIewController を初期化します。それらの 1 つは、UICollectionView を設定する私の GridViewController です。

したがって、この 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 を初期化し、それらのビューをサブビューとして MainViewController に追加します。

これを達成するための最良の方法は何でしょうか?GridViewController とは別に UICollectionViewController を作成する必要がありますか? しかし、この UICollectionView は、画面のどの領域に描画するかをどのように認識しているのでしょうか?

GridCell 内の init メソッドでは、実際にこれを使用して GridCell の下に影を描画します。この init メソッドを使用せずにセルの下に描画するにはどうすればよいですか?

編集2: 上記の編集に加えて:

  • 各 GridCell に UIImageView と UILabel があります。コードでそれらをどのようにターゲットにしますか?
4

1 に答える 1

5

したがって、ここで起こっていることは、かなりの数の点で混乱しています。

  1. あなたの GridCell init メソッドはメンタルです
  2. いくつかの目的の c メソッド パラメーターに名前を付けていません (不適切な形式)。
  3. - (id)initWithSize:(CGFloat)frameWidth :(CGFloat)frameHeight 名前から取得すると予想されるメソッドがありますが、CGSize2つのフロートが必要です
  4. 何らかの理由で、-(id)initWithSize::メソッドを使用してView Controllerを初期化しています
  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 では、メソッドの名前が「initWithSize」であるため、これが CGSize パラメーターを取ることが期待されます。Aは aとCGSizeを持つ C 構造体です。で作ることができます。init メソッドを次のようにします。widthheightCGSizeMake(<width>,<height>)

- (id)initWithSize:(CGSize)size

しかし、あなたは本当に aUIViewControllerで a を開始したくありませんCGSize...

4

UIViewControllerあらゆる種類のサイズや次元を取る init メソッドがないのには理由があります。ビュー コントローラーの考え方は、親 (またはウィンドウ) によって設定されたビューのサイズを持ち、サイズに関係なくビュー内にコンテンツを描画する責任があるということです。UIViewControllerサブクラスとして、UIKit表示する必要があるものを表示するために必要な他のビューとビューコントローラーをロードする場所があります。メソッドをチェックアウトして-(void)viewDidLoadオーバーライドします。UICollectionViewControllerしかし、たとえどんな種類のコンテナも必要とせず、View Controller のビュー プロパティがすでに collectionView であり、他の多くの利点があるため、単純にサブクラス化した方がはるかに良いでしょう。

5

GridIcon.hファイルとGridIcon.mファイルの名前を、それらに含まれるクラスの名前に変更します。あなたのプロジェクトに取り組む他のすべての人ではないにしても、将来のあなたの正気のために、常にこの規則に従ってください。

最後に、クラッシュの理由は ARC やその他のテクノロジの障害によるものではなく、ここでの実装に根本的な問題があるためです。

于 2013-03-15T15:04:06.450 に答える