我有一个UITableView
,只有几行。当我在一行上长按时,将弹出一个菜单,我将可以打开相机拍照。
我创建了一个相册数组,其中包含一个照片数组。我希望每一行将捕获的图片保存到我的“照片”数组中。
当我尝试将照片添加到阵列时,在此行上发生错误Index out of range
的崩溃:albumPhotos[lastIndexPath.row].imagesPath?.append(nameOfPhoto)
这里有一个小演示,反映了我的实际问题:https://github.com/tygruletz/AddPhotosToAlbums
这是我的代码:
class AlbumPhotos {
var imagesPath: [String]
init(imagesPath: [String]) {
self.imagesPath = imagesPath
}
}
protocol AlbumCellDelegate {
func longTapGestureOnCell(_ selectedCell: AlbumCell)
}
class AlbumCell: UITableViewCell {
// Interface Links
@IBOutlet weak var albumNameLabel: UILabel!
@IBOutlet weak var photosImageView: CustomImageView!
// Properties
var delegate: AlbumCellDelegate?
override func awakeFromNib() {
super.awakeFromNib()
let longTapGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.longTapPressed(sender:)))
addGestureRecognizer(longTapGesture)
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
// Detect when the user press Long Tap on any cell
@objc func longTapPressed(sender: UITapGestureRecognizer) {
delegate?.longTapGestureOnCell(self)
}
}
extension AlbumVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return receivedAlbumsType.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "albumCell", for: indexPath) as! AlbumCell
cell.delegate = self // tell the delegate to report everything to this VC
cell.albumNameLabel.text = receivedAlbumsType[indexPath.row].name.capitalized
if albumPhotos.isEmpty {
cell.photosImageView.isUserInteractionEnabled = false
}
else {
let thumbnailImage = albumPhotos[indexPath.row].imagesPath.last ?? String()
cell.photosImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapOnPhotosImageView)))
cell.photosImageView.indexPath = indexPath
cell.photosImageView.isUserInteractionEnabled = true
cell.photosImageView.image = UIImage(named: thumbnailImage)
print("For section \(indexPath.section) - row \(String(describing: indexPath.row)) the album photos are: \(String(describing: albumPhotos[indexPath.row].imagesPath))")
}
return cell
}
@objc func tapOnPhotosImageView(_ sender: UITapGestureRecognizer){
guard let img = sender.view as? CustomImageView, let indexPath = img.indexPath else {return}
selectedIndexPath = indexPath // Get the index of the clicked album of images
print("Index for selected image: \(selectedIndexPath ?? IndexPath())")
if albumPhotos.isEmpty {
print("No photos in the album.")
}
else{
print("There are photos in the album.")
print(albumPhotos.map {$0.imagesPath})
}
}
}
class AlbumVC: UIViewController {
// Interface Links
@IBOutlet weak var albumsTableView: UITableView!
// Properties
var receivedAlbumsType: [AlbumType] = []
var imagePicker = UIImagePickerController()
var cellImageView = UIImageView()
var selectedIndexPath: IndexPath!
var lastIndexPath: IndexPath!
var albumPhotos: [AlbumPhotos] = []
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
albumsTableView.reloadData()
}
func setupViews(){
albumsTableView.tableFooterView = UIView()
albumsTableView.reloadData()
}
}
extension AlbumVC: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
//Dismiss the Camera and display the selected image into the UIImageView
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
imagePicker.dismiss(animated: true, completion: nil)
guard let selectedImage = info[.originalImage] as? UIImage else {
print("Image not found!")
return
}
let randomNumber = arc4random()
let nameOfPhoto = "photo_\(randomNumber).jpeg"
print("Resolution of captured image before resize: \(selectedImage.size)")
print("Index for lastIndexPath.row: \(lastIndexPath.row)")
albumPhotos[lastIndexPath.row].imagesPath?.append(nameOfPhoto)
print("last images from albumPhotos: \(albumPhotos[lastIndexPath.row].imagesPath?[lastIndexPath.row] ?? String())")
albumsTableView.reloadData()
}
}
谢谢阅读!
答案 0 :(得分:1)
我在您的代码中更改了以下文件。因此,请替换这些文件并检查您的应用并分享您的反馈。
AlbumVC.swift
import UIKit
class AlbumVC: UIViewController {
// Interface Links
@IBOutlet weak var albumsTableView: UITableView!
// Properties
var imagePicker = UIImagePickerController()
var cellImageView = UIImageView()
var albumPhotos = [AlbumPhotos]()
var selectedIndexPath: IndexPath!
var lastIndexPath: IndexPath!
override func viewDidLoad() {
super.viewDidLoad()
setupViews()
albumPhotos = DataModel.instance.getAlbumPhotosData(numberOfData: 10)
}
func setupViews(){
albumsTableView.tableFooterView = UIView()
albumsTableView.reloadData()
}
}
extension AlbumVC: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return albumPhotos.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "albumCell", for: indexPath) as! AlbumCell
cell.delegate = self // tell the delegate to report everything to this VC
if albumPhotos.isEmpty {
cell.photosImageView.isUserInteractionEnabled = false
}
else {
let thumbnailImage = albumPhotos[indexPath.row].imagesPath.last ?? String()
cell.photosImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapOnPhotosImageView)))
cell.photosImageView.indexPath = indexPath
cell.photosImageView.isUserInteractionEnabled = true
cell.photosImageView.image = UIImage(named: thumbnailImage)
print("For section \(indexPath.section) - row \(String(describing: indexPath.row)) the album photos are: \(String(describing: albumPhotos[indexPath.row].imagesPath))")
}
return cell
}
@objc func tapOnPhotosImageView(_ sender: UITapGestureRecognizer){
guard let img = sender.view as? CustomImageView, let indexPath = img.indexPath else {return}
selectedIndexPath = indexPath // Get the index of the clicked album of images
print("Index for selected image: \(selectedIndexPath ?? IndexPath())")
if albumPhotos.isEmpty {
print("No photos in the album.")
}
else{
print("There are photos in the album.")
print(albumPhotos.map {$0.imagesPath})
}
}
}
extension AlbumVC: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
//Dismiss the Camera and display the selected image into the UIImageView
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
imagePicker.dismiss(animated: true, completion: nil)
guard let selectedImage = info[.originalImage] as? UIImage else {
print("Image not found!")
return
}
let randomNumber = arc4random()
let nameOfPhoto = "photo_\(randomNumber).jpeg"
print("Resolution of captured image before resize: \(selectedImage.size)")
print("Index for lastIndexPath.row: \(lastIndexPath.row)")
albumPhotos[lastIndexPath.row].imagesPath.append(nameOfPhoto)
print("last images from albumPhotos: \(albumPhotos[lastIndexPath.row].imagesPath )")
albumsTableView.reloadData()
}
}
extension AlbumVC: AlbumCellDelegate {
// Delegate function to detect on which cell was pressed a LongTapGesture
func longTapGestureOnCell(_ selectedCell: AlbumCell) {
showOptionsOnCellTapped(albumsTableView.indexPath(for: selectedCell)!)
}
func showOptionsOnCellTapped(_ indexPath: IndexPath) {
let addPhoto = UIAlertAction(title: " Add Photo", style: .default) { action in
self.lastIndexPath = indexPath
print("Add Photo - LastIndexPath: \(self.lastIndexPath ?? IndexPath())")
self.showCamera(imagePicker: self.imagePicker)
}
let actionSheet = configureActionSheet()
actionSheet.addAction(addPhoto)
self.present(actionSheet, animated: true, completion: nil)
}
// Open camera
func showCamera(imagePicker: UIImagePickerController) {
imagePicker.delegate = self
imagePicker.sourceType = .camera
present(imagePicker, animated: true, completion: nil)
}
// Configure an UIActionSheet to work for iPhone and iPad. If the user use an iPad then the ActionSheet will be displayed in the middle of the screen.
func configureActionSheet() -> UIAlertController {
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
let cancel = UIAlertAction(title: "Cance;", style: .cancel, handler: nil)
actionSheet.addAction(cancel)
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiom.pad ){
actionSheet.popoverPresentationController?.sourceView = self.view
actionSheet.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.midY, width: 0, height: 0)
actionSheet.popoverPresentationController?.permittedArrowDirections = []
}
return actionSheet
}
}
并添加了此文件以为您的应用 DataModel.Swift
创建黑色数据class DataModel {
static let instance = DataModel()
private init() {
}
func getAlbumPhotosData(numberOfData: Int) -> [AlbumPhotos] {
var albumPhotos = [AlbumPhotos]()
for _ in 1...numberOfData {
let objAlbum = AlbumPhotos(imagesPath: [])
albumPhotos.append(objAlbum)
}
return albumPhotos
}
}
,并在文件 AlbumPhotos.swift 下进行更改
import Foundation
class AlbumPhotos {
var imagesPath: [String]
init(imagesPath: [String]) {
self.imagesPath = imagesPath
}
}
答案 1 :(得分:0)
albumPhotos[lastIndexPath.row].imagesPath?.append(nameOfPhoto)
那时,albumPhotos为空,因此无法从该数组位置获得AlbumPhotos对象。
您需要在每个单元格的索引行中添加一个AlbumPhotos对象 或者您可以通过将索引作为关键字来选择字典。
答案 2 :(得分:0)
class AlbumPhotos {
var imagesPath: [UIImage]
init(imagesPath: [UIImage]) {
self.imagesPath = imagesPath
}
}
extension AlbumVC: AlbumTypeVCDelegate {
func receivedAlbumType(name: String) {
albumPhotos.append(AlbumPhotos(imagesPath: [UIImage]()))
receivedAlbumsType.append(AlbumType(name: name))
}
}
extension AlbumVC: UINavigationControllerDelegate, UIImagePickerControllerDelegate {
//Dismiss the Camera and display the selected image into the UIImageView
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]){
imagePicker.dismiss(animated: true, completion: nil)
guard let selectedImage = info[.originalImage] as? UIImage else {
print("Image not found!")
return
}
let randomNumber = arc4random()
let nameOfPhoto = "photo_\(randomNumber).jpeg"
print("Resolution of captured image before resize: \(selectedImage.size)")
print("Index for lastIndexPath.row: \(lastIndexPath.row)")
albumPhotos[lastIndexPath.row].imagesPath.append(selectedImage)
// print("last images from albumPhotos: \(albumPhotos[lastIndexPath.row].imagesPath.last ?? String())")
albumsTableView.reloadData()
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "albumCell", for: indexPath) as! AlbumCell
cell.delegate = self // tell the delegate to report everything to this VC
cell.albumNameLabel.text = receivedAlbumsType[indexPath.row].name.capitalized
if albumPhotos.isEmpty {
cell.photosImageView.isUserInteractionEnabled = false
}
else {
let thumbnailImage = albumPhotos[indexPath.row].imagesPath.last ?? UIImage()
cell.photosImageView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tapOnPhotosImageView)))
cell.photosImageView.indexPath = indexPath
cell.photosImageView.isUserInteractionEnabled = true
cell.photosImageView.image = thumbnailImage//UIImage(named: thumbnailImage)
print("For section \(indexPath.section) - row \(String(describing: indexPath.row)) the album photos are: \(String(describing: albumPhotos[indexPath.row].imagesPath))")
}
return cell
}
请尝试在您的项目中更改以上代码。