Как передать изображение как переменную в UIImageView в отдельном View Controller? - PullRequest
0 голосов
/ 06 января 2019

Я извлекаю некоторые данные JSON и отображаю их в UITableView (iOS / iPhone 8). Он отображает изображение, заголовок и описание каждого значения. Однако я успешно справился с этим, но у меня возникли проблемы с переносом изображения в отдельный контроллер просмотра.

Под этим я подразумеваю, что при касании ячейки на первом контроллере представления открывается другой контроллер представления, отображающий только информацию из этой ячейки.

Мне удалось сделать заголовок и описание доступными через глобальную переменную и indexPath. Но то же самое не относится к изображению из-за конфликта со строками.

Я перечислил ниже, что я успешно сделал со строками заголовка и описания, а затем покажу свое предложение (что, конечно, не работает).

Как я могу получить изображение, которое уже было загружено и находится в массиве, чтобы быть доступным, как у меня уже есть с заголовком и описанием, для использования в другом View Controller?

Код, который форматирует и собирает значения из JSON:

if let jsonData = myJson as? [String : Any] { // Dictionary
    if let myResults = jsonData["articles"] as? [[String : Any]] {
        // dump(myResults)

        for value in myResults {
            if let myTitle = value["title"] as? String {
                // print(myTitle)
                myNews.displayTitle = myTitle
            }

            if let myDesc = value["description"] as? String {
                myNews.displayDesc = myDesc
            }

            if let mySrc = value["urlToImage"] as? String {
                // print(mySrc)
                myNews.src = mySrc
            }

            self.myTableViewDataSource.append(myNews)
            // dump(self.myTableViewDataSource)

            // GCD
            DispatchQueue.main.async {
                self.myTableView.reloadData()
            }

        }
    }
} 

Две переменные у меня есть вне класса, чтобы использовать их глобально:

var petsIndex = ""
var petsDesc = "" 

Код, который работает с UITableView и его ячейками:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     let myCell = tableView.dequeueReusableCell(withIdentifier: "reuseCell", for: indexPath)

     let myImageView = myCell.viewWithTag(2) as! UIImageView
     let myTitleLabel = myCell.viewWithTag(1) as! UILabel

     myTitleLabel.text = myTableViewDataSource[indexPath.row].displayTitle

    let myURL = myTableViewDataSource[indexPath.row].src
    loadImage(url: myURL, to: myImageView)

    return myCell
}  

Код, который я использую для отправки значений JSON в другой View Controller. Я достигаю этого, используя эти глобальные переменные:

// If a cell is selected, view transitions into a different view controller.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    petsIndex = self.myTableViewDataSource[indexPath.row].displayTitle
    petsDesc = self.myTableViewDataSource[indexPath.row].displayDesc

    // Img needs to go here

     myIndex = indexPath.row
     performSegue(withIdentifier: "segue", sender: self)

 } 

Вот что я делал, чтобы решить мою проблему. Я преобразовал строку в UIImage? или UIImageView? и передал ее как данные. Я оставил переменную пустой и менял ее по мере поступления данных. Это произойдет, когда ячейка будет нажата. Затем внутри второго View Controller я бы использовал IBOutlet для UIImageView:

// Variable outside of the class
var petsImg: UIImageView? = nil

petsImg = self.myTableViewDataSource[indexPath.row].src 

В этот момент я в тупике. Я получил ошибки об изображении, являющемся строкой и должно быть преобразовано. И когда она была преобразована, переменная всегда возвращалась пустой или ноль.

Обновление: Я просто пытался сделать это. Работает и не выдает никаких ошибок. Тем не менее, я все еще получаю значение nil

petsImg = UIImage(named: self.myTableViewDataSource[indexPath.row].src)

Ответы [ 3 ]

0 голосов
/ 06 января 2019

Когда вы выполняете переход, вы можете перехватить вызов, чтобы подготовить контроллер представления, который он показывает. Вид этого контроллера на данный момент еще не загружен, поэтому вам нужно будет создать свойства внутри вашего PostViewController; Вы можете создать свойства для заголовка, описания и изображения.

Тем не менее, будет намного проще передать эту информацию как ваш NewsInfo объект, например:

struct NewsInfo {
    let displayTitle: String
    let displayDesc: String
    let src: String

    var imageURL: URL { return URL(string: src)! }
}

А также пользовательский класс ячейки, который принимает объект NewsInfo в качестве аргумента для заполнения торговых точек.

class NewsInfoTableViewCell: UITableViewCell {        
    var newsInfo: NewsInfo? {
        didSet {
            updateOutlets()
        }
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        newsInfo = nil
    }

    private func updateOutlets() {
        textLabel?.text = newsInfo?.displayTitle
        detailTextLabel?.text = newsInfo?.displayDesc
        // loadImage()
    }
}

Установите пользовательский класс ячейки таблицы и установите свойство newsInfo после снятия с очереди.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseCell", for: indexPath) as! NewsInfoTableViewCell
    cell.newsInfo = myTableViewDataSource[indexPath.row]
    return cell
}

Когда ячейка выбрана, вы можете передать ее в качестве отправителя для выполнения перехода, а не устанавливать глобальные переменные для заполнения PostViewController в viewDidLoad.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if let cell = tableView.cellForRow(at: indexPath) as? NewsInfoTableViewCell {
        performSegue(withIdentifier: "segue", sender: cell)
    }
}

Вы можете удалить весь этот метод, если вы замените существующий переход путем перетаскивания с помощью ctrl из ячейки прототипа в PostViewController в IB, чтобы сделать ячейку отправителем перехода.

Мы хотим этого, потому что мы перехватим переход, чтобы подготовить контроллер представления назначения, передав ему объект NewsInfo ячейки, которая была выбрана и запустила переход.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    switch (segue.destination) {
    case (let controller as PostViewController, let cell as NewsInfoTableViewCell):
        controller.newsInfo = cell.newsInfo
    default:
        break
    }
}

Аналогично тому, как мы передаем объект NewsInfo в ячейку для заполнения торговых точек, вы можете сделать то же самое для PostViewController.

0 голосов
/ 06 января 2019

Похоже, ваше изображение не изображение, а URL-адрес изображения. Вы можете загружать изображения в представления изображений, используя такую ​​библиотеку, как nuke: https://github.com/kean/Nuke

Поскольку сетевые запросы вызываются асинхронно, немного сложно понять, в какой момент вы пытаетесь настроить UIImageView. Но как только вы получите свой сетевой ответ, вы сделаете одно из двух:

  1. Если ваш контроллер представления еще не загружен (т.е. вы загружаете его после завершения сетевого ответа), вы можете настроить UIImageView в методе подготовки к продолжению.
  2. Если ваш контроллер представления уже загружен (что вполне нормально), вам нужно будет установить ссылку на этот контроллер представления в методе подготовки к переходу. Затем вы можете настроить контроллер представления после выполнения сетевого запроса. Я бы сделал ссылку на этот VC слабой, так как система (стек навигации) уже сильно держится за VC.

PS: Я предлагаю вам десериализовать ваш ответ JSON на объект. Это поможет нам понять ваш код. Трудно увидеть вашу проблему, когда вы передаете словарные объекты. Я предлагаю вам использовать одно из следующего: 1. Кодируемый протокол 2. ObjectMapper 3. MapCodableKit (это моя библиотека, которой я пользуюсь лично)

PPS: я предположил, что вы используете раскадровки.

0 голосов
/ 06 января 2019

Быстрый и грязный раствор

В вашем контроллере второго просмотра загрузите изображение, используя:

// With petsImg being the url to your image:
if let url = URL(string: petsImg), let imageData = Data(contentsOf: url) { 
    imagePost.image = UIImage(data: data)
}

Правильное решение

Вы не должны работать с глобальными переменными для передачи данных из одного контроллера представления в другой ( прочитайте почему ). Вместо этого посмотрите ответ на этот вопрос, чтобы узнать, как перенести данные (в вашем случае: объект myNews) из табличного представления в подробное представление: Отправка данных из TableView в DetailView Swift

Если это слишком абстрактно, вы можете посмотреть этот урок. Он охватывает то, что вы хотите сделать: https://www.raywenderlich.com/265-uisplitviewcontroller-tutorial-getting-started

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...