L'une des spécifications de mon application est que, en tapotant une cellule tableView, l'utilisateur sera redirigé vers le site Web associé à la cellule. Voici le code:
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let url = NSURL(string: appdelegate.studentInfo[indexPath.row].url) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
UIApplication.sharedApplication().openURL(url)
}
else {
let alert = UIAlertController(title: "Invalid URL", message: "Cannot open URL because it is invalid.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
Lors de mon premier contact, l'URL s'ouvre comme il se doit. Toutefois, si vous revenez dans l’application depuis Safari et que vous touchez une autre cellule, le message d'erreur suivant apparaît, même si l'application fonctionne toujours comme il est supposé:
La capture instantanée d’une vue qui n’a pas été rendue donne un. Vide instantané. Assurez-vous que votre vue a été rendue au moins une fois avant instantané ou instantané après les mises à jour de l'écran.
Y a-t-il un moyen d'éviter cette erreur? Ou est-ce un bug?
J'ai expérimenté des blocs dispatch_async mais cela n'a pas résolu le problème.
Ce n'est peut-être pas le même problème que moi, mais je viens de résoudre le même avertissement dans mes journaux.
Je présente une UIAlertController
sous la forme d'une popover d'actionSheet sur un iPad et j'ai eu exactement le même avertissement 8 fois de suite à chaque fois que j'ai essayé d'afficher le contrôleur d'alerte.
Pour que l'avertissement disparaisse, tout ce que j'avais à faire était de disposer la vue du contrôleur d'alertes comme dans le code suivant:
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
...
alertController.view.layoutIfNeeded() //avoid Snapshotting error
self.presentViewController(alertController, animated: true, completion: nil)
J'espère que cela vous aide ou aide toute autre personne à avoir le même avertissement.
Également en utilisant Objective-C, l’utilisation du [modeAlert.view layoutIfNeeded]
suggéré a réduit le nombre d’erreurs à un, comme ci-dessus. L’erreur finale a été supprimée en remplaçant le dernier addAction de UIAlertActionStyleCancel
par UIAlertActionStyleDefault
comme ci-dessous. Pas une bonne solution de rechange à ce qui semble être un bug.
[modeAlert addAction:[UIAlertAction
actionWithTitle:NSLocalizedString(@"Cancel", @"")
style:UIAlertActionStyleDefault
handler:nil ]];
Je pense que le dernier avertissement est venu du bouton Annuler.
Sur iOS8, le bouton d'annulation n'apparaît qu'en cas de besoin. Si vous exécutez l'application sur iPhone, elle est visible. Si vous exécutez l'application sur iPad, le bouton d'annulation n'est pas affiché et le gestionnaire de l'action d'annulation (style: UIAlertActionStyleCancel) est appelé lorsque l'utilisateur appuie en dehors du menu contextuel.
la réponse vient de: la réponse d'amalicka
Je déclenche une UIAlertControllerStyleActionSheet
UIAlertController
après que l'utilisateur a cliqué sur une UITableViewRowAction
et le même message d'erreur a été répété 8 fois après avoir présenté la UIAlertController
.
Sur l'iPad Pro Simulator pour iOS 9.3, j'ai essayé la réponse de Saliom , et je suis passé de huit messages de journal à un.
Comme suggéré par anorskdev , je mets mon appel à -[UIView layoutIfNeeded]
après mon appel -[UIViewController presentViewController:animated:completion:]
et tous les avertissements disparaissent:
- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewRowAction *moreAction =
[UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault
title:@"More"
handler:^(UITableViewRowAction * _Nonnull action,
NSIndexPath * _Nonnull moreIndexPath)
{
UIAlertController *alertController =
[UIAlertController alertControllerWithTitle:name
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *deleteAlertAction =
[UIAlertAction actionWithTitle:@"Delete"
style:UIAlertActionStyleDestructive
handler:deleteAction];
[alertController addAction:deleteAlertAction];
UIAlertAction *cancelAlertAction =
[UIAlertAction actionWithTitle:@"Cancel"
// totally ok to use the proper
// UIAlertActionStyleCancel
style:UIAlertActionStyleCancel
handler:cancelAction];
[alertController addAction:cancelAlertAction];
CGRect sourceRect = [self.tableView rectForRowAtIndexPath:moreIndexPath];
// You must specify a sourceRect and sourceView
// or a barButtonItem or presenting a
// UIAlertControllerStyleActionSheet UIAlertController
// will crash on iPad.
alertController.popoverPresentationController.sourceRect = sourceRect;
alertController.popoverPresentationController.sourceView = self.tableView;
// first, present the alertController
[self presentViewController:alertController
animated:YES
completion:nil];
// then -layoutIfNeeded
[alertController.view layoutIfNeeded];
}
return @[
moreAction,
];
}
Notez qu'il n'était pas nécessaire d'utiliser la solution de Patrick d'utiliser UIAlertActionStyleDefault
pour cancelAlertAction
ou la solution de nurider de l'éliminer complètement sur les iPads.
Je recevais un avertissement de débogage similaire lorsque j'essayais de présenter QLPreviewController sous forme modale. J'ai lu sur d'autres articles qu'il s'agissait d'un bogue Xcode.
Pour moi, l'erreur affichée lorsque j'ai exécuté mon application sur le simulateur mais pas sur un appareil réel. Doit être un problème de Xcode/Simulator. J'espère que cela pourra aider.
Je faisais face au même problème (même avertissement XD).
L'instantané d'une vue qui n'a pas été rendue donne un instantané vide. Assurez-vous que votre vue a été rendue au moins une fois avant la prise de vue ou après la mise à jour de l'écran.
Ma version de Xcode est 9.4.1 , et tout était parfait jusqu'à ce que j'ajoute resignFirstResponder()
dans textFieldShouldReturn(_ textField: UITextField)
.
Lorsque j'ai touché UITextField
avec text dans la UITableViewCell
, cela montrera l'avertissement.
J'ai donc changé la manière de déclencher UITextField
( Edit version ). Il ne montre plus l'avertissement.
En conclusion, je ne sais toujours pas pourquoi cela est arrivé, mais ce que je peux faire, c'est éviter l'avertissement, espérons que cela aidera quelqu'un: D
class TableViewCell: UITableViewCell {
// add this in TableViewCell
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
answerTextField.isEnabled = selected
if selected {
answerTextField.becomeFirstResponder()
} else {
answerTextField.resignFirstResponder()
}
}
}
class ViewController: UIViewController {
private let tableView: UITableView = {
let t = UITableView()
t.separatorStyle = .none
t.backgroundColor = .clear
return t
}()
private let cellId = "Cell"
private let data = [
Model(title: "A", answer: "a"),
Model(title: "B", answer: "b"),
Model(title: "C", answer: nil),
Model(title: "D", answer: nil)
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
tableView.register(TableViewCell.self, forCellReuseIdentifier: cellId)
view.addSubview(tableView)
tableView.frame = view.frame
}
}
extension ViewController: UITableViewDataSource, UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as? TableViewCell {
cell.contentView.backgroundColor = indexPath.section % 2 == 0 ? .gray : .white
cell.setData(data[indexPath.row])
return cell
}
return UITableViewCell()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
}
class TableViewCell: UITableViewCell {
private let titleLabel = UILabel()
private let answerTextField = UITextField()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupViews()
}
func setupViews() {
setupTitleLabels()
}
func setData(_ data: Model) {
titleLabel.text = data.title
answerTextField.text = data.answer
}
private func setupTitleLabels() {
answerTextField.delegate = self
let sv = UIStackView(arrangedSubviews: [titleLabel, answerTextField])
sv.axis = .vertical
sv.spacing = 0
sv.distribution = .fill
contentView.addSubview(sv)
sv.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
sv.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true
sv.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
sv.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true
}
}
extension TableViewCell: UITextFieldDelegate {
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
struct Model {
let title: String
var answer: String?
init(title: String, answer: String? = nil) {
self.title = title
self.answer = answer
}
}
Pour éviter le copier/coller de la réponse de Saliom vous pouvez créer une telle sous-classe et l'utiliser au lieu de UIAlertController
:
class AlertController: UIAlertController {
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
self.view.layoutIfNeeded()
}
}