如何将UIImage数组添加到集合视图中

3

感谢您查看此项目并帮助我。

故事板连接

我正在尝试在我的集合视图中显示一个UIImage数组。 我已经在故事板中连接了一切。
我的ViewController既是Collection View的委托又是数据源。
我的单元格包含一个UIImageView,它在我的自定义单元格的头文件中具有IBOutlet。

应用程序当前的工作方式

  1. 应用程序从维基百科API创建一个图像数组,该API基于用户的搜索。
  2. 一旦用户输入他或她的搜索,ViewController将NSString传递给模型(GetImageURL.h和GetImageURL.m)。
  3. 这似乎是基于我使用的NSLog的。
  4. 模型设置好UIImages数组后将其传回控制器。
  5. 然后,ViewController尝试重新加载collectionView的数据,应用程序崩溃。

错误消息如下:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'UICollectionView must be initialized with a non-nil layout parameter'
*** First throw call stack: 
(0x1c97012 0x10d4e7e 0x1c96deb 0x518748 0x533b1b 0x533646 0xf9ff8 0xfa232 0x5338d5 0x29a4 0x3ef6 0xb13fb4 0xb13e67 0x30ca 0x49fb53f 0x4a0d014 0x49fd7d5 0x1c3daf5 0x1c3cf44 0x1c3ce1b 0x1bf17e3 0x1bf1668 0x18ffc 0x1b9d 0x1ac5)
libc++abi.dylib: terminate called throwing an exception


我的问题

我想知道在创建collectionView时,出了什么问题导致在稍后调用reloadData时它崩溃。

代码

ViewController.h

#import <UIKit/UIKit.h>

@interface ViewController : UICollectionViewController <UICollectionViewDelegateFlowLayout, UICollectionViewDataSource, UIApplicationDelegate>

//receives a mutable array of UIImage(s)
-(void)receiveArrayOfImages: (NSMutableArray *)arrayOfImages;
@end


ViewController.m

#import "ViewController.h"
#import "Cell.h"
#import "GetImageURL.h"

NSString *kCellID = @"cellID";

@interface ViewController () {
    UISearchBar *searchBar;
}
@property (nonatomic, strong) NSString *searchBarText;
@property (strong, nonatomic) NSMutableArray *arrayOfImages;

@end

@implementation ViewController

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    if ([self.arrayOfImages count] > 0) {
        NSLog(@"return %d items for collection view", [self.arrayOfImages count]);
        return [self.arrayOfImages count];
    } else {
        NSLog(@"returned 0 items for collection view");
        return 0;
    }
}

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

    NSLog(@"cellForItemAtIndexPath");

    Cell *cell = [cv dequeueReusableCellWithReuseIdentifier:kCellID forIndexPath:indexPath];
    int row = [indexPath row];
    cell.cellImage.image = [self.arrayOfImages objectAtIndex:row];
    return cell;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    //Creates a Search Bar Button System Item.
    UIBarButtonItem *searchButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSearch target:self action:@selector(tapSearchButton:)];
    self.navigationItem.rightBarButtonItem = searchButton;
}


-(void)tapSearchButton:(id)sender {
    //Adds or takes away searchbar on navigationbar.
    if (!searchBar) {
        searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(-5.0, 0.0, 320.0, 44.0)];
        searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        UIView *searchBarView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 310.0, 44.0)];
        searchBarView.autoresizingMask = 0;
        searchBar.delegate = self; //this line causes a warning. "Assigning to 'id<UISearchBarDelegate> from incompatible type 'ViewController *cons_strong"
        [searchBarView addSubview:searchBar];
        self.navigationItem.titleView = searchBarView;
        [searchBar becomeFirstResponder];
    } else {
        self.navigationItem.titleView = nil;
        searchBar = nil;
    }
}

- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar {
    GetImageURL *bookName = [[GetImageURL alloc] init];
    bookName.bookName = [searchBar text]; //this line causes a warning. "Local declaration of 'searchBar' hides instance variable"
    NSLog(@"In ViewController, the book name is: %@", bookName.bookName);
    [bookName recieveBookUrl:bookName.bookName];
    [self.view endEditing:YES];
}

-(void)receiveArrayOfImages: (NSMutableArray *)arrayOfImages {
    //receives an array of UImages called arrayOfImages and sets it to self.arrayOfImages
    self.arrayOfImages = arrayOfImages;
    NSLog(@"This is the array of UIimages in ViewController.m: %@", self.arrayOfImages);

    [self.collectionView reloadData]; //This line causes the app the crash. "Reason: UICollectionView must be initialized with a non-nil layout parameter"
}

@end


Cell.h

#import <UIKit/UIKit.h>

@interface Cell : UICollectionViewCell

//UIImageView inside Custom Cell
@property (strong, nonatomic) IBOutlet UIImageView *cellImage;

@end


Cell.m

#import "Cell.h"

@implementation Cell

- (id)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {
    }
    return self;
}

@end


GetImageURL.h

#import <Foundation/Foundation.h>
#import "ViewController.h"

@interface GetImageURL : NSObject

@property (strong, nonatomic) NSString *bookName;
@property (strong, nonatomic) NSMutableArray *imageArray;

-(void)recieveBookUrl:(NSString *)bookName; //recieves a string from the viewController that the user inputs

@end


GetImageURL.m

#import "GetImageURL.h"

@interface GetImageURL()

@property (strong, nonatomic) NSString *pageID;
@property (strong, nonatomic) NSMutableArray *imageUrlArray;

@end


@implementation GetImageURL

//takes the string that the user entered and alters it to fit the wikipedia API format
-(void)recieveBookUrl:(NSString *)bookName {
    self.imageUrlArray = [[NSMutableArray alloc] init];
    self.imageArray = [[NSMutableArray alloc] init];
    bookName = [bookName stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //or use string by replacing @" " with @"%20";
    NSString *wikiAPI  = @"http://en.wikipedia.org/w/api.php?format=json&indexpageids&action=query&prop=images&titles=";
    bookName = [wikiAPI stringByAppendingString:bookName];
    NSURL *bookURL = [NSURL URLWithString:bookName];
    //Plan to put this action in the background later
    dispatch_async(dispatch_get_main_queue(), ^() {
        NSData *data = [NSData dataWithContentsOfURL:bookURL];
        [self performSelectorOnMainThread:@selector(getBookTitleApi:) withObject:data waitUntilDone:YES];
    });
}

//first part of the API sucessfully gets the padeID and all the images returned by the API.
-(void)getBookTitleApi: (NSData *)data {
    NSError *error;
    NSDictionary *json = [NSJSONSerialization
                          JSONObjectWithData:data
                          options:kNilOptions
                          error:&error];
    NSDictionary *parseQueryBookTitle = [json objectForKey:@"query"];
    NSArray *parsePageIdsBookTitle = [parseQueryBookTitle objectForKey:@"pageids"];
    for (NSDictionary *pageIdBookTitle in parsePageIdsBookTitle) {
        self.pageID = [NSString stringWithFormat:@"%@", pageIdBookTitle];
    }

    NSDictionary *parsePagesBookTitle = [parseQueryBookTitle objectForKey:@"pages"];
    NSDictionary *parsePageIdBookTitle = [parsePagesBookTitle objectForKey:self.pageID];
    NSDictionary *parseImagesBookTitle = [parsePageIdBookTitle objectForKey:@"images"];
    NSDictionary *valueTitleBookTitle = [parseImagesBookTitle valueForKey:@"title"];

    for (NSDictionary *imageFilenames in valueTitleBookTitle) {
        NSString *imageFilename = [NSString stringWithFormat:@"%@", imageFilenames];
        imageFilename = [imageFilename substringFromIndex:5];
        imageFilename = [imageFilename stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; //or use string by replacing @" " with @"%20";

        NSString *wikiImageAPI = @"http://en.wikipedia.org/w/api.php?action=query&format=json&indexpageids&prop=imageinfo&iiprop=url&titles=Image:";
        imageFilename = [wikiImageAPI stringByAppendingString:imageFilename];

        NSURL *imageFilenameUrl = [NSURL URLWithString:imageFilename];
        NSData *data = [NSData dataWithContentsOfURL:imageFilenameUrl];
        [self performSelectorOnMainThread:@selector(getImageApi:) withObject:data waitUntilDone:YES];
    }
    //Uses the URLs to create an NSData object and then uses that data to create a UIImage which is added to a Mutable Array
    for (NSString *jpgURL in self.imageUrlArray) {
        NSURL *imageURL = [NSURL URLWithString:jpgURL];
        NSLog(@"This is an imageURL in GetImageURL.m: %@", imageURL);
        NSData *data = [NSData dataWithContentsOfURL:imageURL];
        UIImage *image = [UIImage imageWithData:data];
        [self.imageArray addObject:image];
    }


    NSLog(@"The array of images in GetImageURL.m contains %d images called %@", [self.imageArray count], self.imageArray);
    ViewController *view = [[ViewController alloc] init];
    [view receiveArrayOfImages:self.imageArray]; //sends the array of images to the View Controller

    //objects removed from array so that next user search can start over
    [self.imageArray removeAllObjects];
    [self.imageUrlArray removeAllObjects];
}

//Uses the image filenames from the first section and gets the specific URLS for the image. Limits results to .jpg images
-(void)getImageApi: (NSData *)data {
    NSError *error;
    NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];

    NSDictionary *parseQueryImage = [json objectForKey:@"query"];
    NSDictionary *parsePageIdsImage = [parseQueryImage objectForKey:@"pageids"];

    for (NSString *pageIdImage in parsePageIdsImage) {
        NSDictionary *parsePagesImage = [parseQueryImage objectForKey:@"pages"];
        NSDictionary *parsePageIdImage = [parsePagesImage objectForKey:pageIdImage];
        NSDictionary *parseImageInfoImage = [parsePageIdImage objectForKey:@"imageinfo"];
        NSDictionary *valueImageInfoUrlsImage = [parseImageInfoImage valueForKey:@"url"];

        for (NSString *valueImageInfoUrlImage in valueImageInfoUrlsImage) {

            if ([valueImageInfoUrlImage hasSuffix:@".jpg"]) {
                [self.imageUrlArray addObject:valueImageInfoUrlImage];
            }
        }
    }
}

@end


抱歉在这里放置了所有的代码。我想这样做会更容易,因为所有内容都在这里。也许对其他人也有帮助。

谢谢!


也许这能帮到你:https://dev59.com/8GMm5IYBdhLWcg3wHMJ0#17856406 - Prince Kumar Sharma
3个回答

0
如果您的集合视图单元格不是在故事板中创建的,那么我认为您必须注册它。
如果您的单元格是编程的。
// Add this in your controller's viewDidLoad method
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kCellID];

如果你的单元格有一个nib文件,我认为应该使用registerNib:forCellWithReuseIdentifier:方法进行注册。

感谢您的评论。我正在使用原型单元格,我在某个地方读到过并尝试在Storyboard中与Collection View Controller一起使用。我是否最好通过编程方式创建单元格?我在Apple的文档中找到了registerClass:,但它没有帮助,所以我将其删除了。还有其他想法吗?再次感谢您的帮助。 - Daniel

0

你的布局设置为流式了吗?在你的Storyboard中应该是这样的:

Collection view layout screenshot

如果您将其设置为自定义,则需要自己创建布局。


除了为我的单元格分配正确的类并更改其重用ID之外,我没有更改任何设置。感谢您的帮助! - Daniel

-1
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
    return array.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    static NSString *identifier = @"Cell";
    UIImage *smallimage = [UIImage imageNamed:[NSString StringWithFormat:@"%@.png"[array[indexpath]]];

      UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];

    UIImageView *gridimageview = (UIImageView *)[cell viewWithTag:100];
    [gridimageview setImage:smallimage];
    return cell;

}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
    NSLog(@"index path is %d", indexPath.row);
   //Enter the action you want when an image is clicked in collection view
    }
- (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
//    Write your code here to  deselect the selected image
    }
}

谢谢你的回复。我在处理你的代码时遇到了一些问题,虽然我同意cellForItemAtIndexPath:可能是我的问题所在。我在创建UIImage *small image以及下面那行代码时都出现了错误。此外,如果我的数组已经包含UIImages,我是否需要创建另一个UIImage?再次感谢您的帮助! - Daniel
现在尝试运行这段代码,检查是否已经在Storyboard中为你的CollectionViewCell内的ImageView设置了标签100。请确保数组的索引使用你的数组名称。 - ArunMak
我在Storyboard中将单元格的标签设置为100,并用self.arrayOfImages替换了“array [indexpath]”。应该是self.arrayOfImages[indexPath]吗?我收到一个错误,说UICollectionView必须使用非空布局参数进行初始化。 - Daniel
你需要在你的故事板上为集合视图控制器设置一个标识符,否则它不会返回任何东西。 - ArunMak
在集合视图控制器的身份检查器中,我将故事板 ID 和恢复 ID 设置为 collectionViewController。我需要在我的代码中使用它吗? - Daniel
请检查您是否已为UIcollectionView设置了数据源和代理,并检查您是否已将位于uicollectionviewcell内部的imageview标记设置为100,还要检查您是否已将标识符设置为Cell以用于uicollectionviewcell。如果您正在使用上述代码,则适用此内容。 - ArunMak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接