Alguém aqui no SO queria alterar o comportamento dos UIAlertAction
botões em um arquivo específico UIAlertController
, mas não em outros. (Eles queriam rótulos de botões multilinhas para um alerta, mas comportamento normal para todos os outros alertas.) ( Aqui está um link para a outra pergunta.)
Se você ler a documentação, UIAlertController
diz que
A classe UIAlertController deve ser usada como está e não oferece suporte a subclasses. A hierarquia de visualizações desta classe é privada e não deve ser modificada.
Como experiência, decidi tentar criar uma subclasse vazia e fictícia de UIAlertController
, apenas para ter um nome de classe para dar ao método UIAppearanceappearance(whenContainedInInstancesOf:)
A definição da subclasse fictícia é apenas esta:
class FooController: UIAlertController {
}
Isso então me permite usar a declaração
UILabel.appearance(whenContainedInInstancesOf: [FooController.self]).numberOfLines = 2
e substituir a aparência de UILabel
s especificamente em instâncias deFooController
Funciona, aparentemente perfeitamente.
Você pode baixar o projeto de amostra do Github aqui .
Quando você cria um vanilla UIAlertController
, seus UIAlertAction
botões têm rótulos de linha única normalmente. Quando você cria um FooController
, seus UIAlertAction
botões possuem rótulos de múltiplas linhas.
Embora pareça funcionar perfeitamente, estou desconfiado de ir contra uma declaração explícita nos documentos da Apple de não subclassificar UIAlertController
.
Quais são os riscos de ignorar essa advertência e usar uma subclasse vazia?
Aqui está o código do meu projeto de exemplo para referência:
import UIKit
class FooController: UIAlertController {
}
class ViewController: UIViewController {
let buttonLabels = [
"""
Button1
line2
""",
"""
Button2
line2
""",
"""
Button3
line2
"""
]
@IBAction func handleAlertButton(_ sender: Any) {
presentAlert(type: UIAlertController.self)
}
@IBAction func handleFooButton(_ sender: Any) {
presentAlert(type: FooController.self)
}
override func viewDidLoad() {
super.viewDidLoad()
UILabel.appearance(whenContainedInInstancesOf: [FooController.self]).numberOfLines = 2
}
func presentAlert(type: UIAlertController.Type) {
let sheet = type.init(title: type.description(), message: nil, preferredStyle: .actionSheet)
for buttonTitle in buttonLabels {
let item = UIAlertAction(title: buttonTitle, style: .default) { (action) in
print("Button \(buttonTitle) tapped")
}
sheet.addAction(item)
}
present(sheet, animated: true, completion: nil)
}
}
Quais são os riscos de ignorar essa advertência e usar uma subclasse vazia?
UIAlertController
pode não funcionar corretamente em uma atualização futura do iOS.UILabel.appearance
) da subclasse pode não funcionar corretamente em uma atualização futura do iOS.Esses são os possíveis riscos.
Embora a Apple sempre tenha a palavra final, é altamente improvável que a Apple rejeite um aplicativo simplesmente porque você subclassificou
UIAlertController
dessa maneira. Eu pessoalmente subclassifiquei várias classes do UIKit que a Apple diz que não deveriam ser subclassificadas. Fiz isso em um aplicativo que está na app store há muitos anos e teve muitas atualizações. Você não está usando nenhuma API privada. E a Apple não diz que você não pode criar subclasses deUIAlertController
. Diz que a classe não se destina a ser subclassificada.Isso leva ao risco nº 2. A Apple afirma que
UIAlertController
não se destina a ser subclassificado e não oferece suporte a subclasses. Isso significa que ele não fornece nenhuma API que deva ser substituída ou modificada. Mas isso não significa que você não possa subclassificá-lo para adicionar métodos auxiliares, por exemplo. Ou simplesmente para dar um novo nome à classe para que você possa fazer coisas como o seuUILabel.appearance
. Sua subclasse é benigna e não tenta modificar a funcionalidade ou se aprofundar na estrutura da subvisão privada. É uma subclasse "segura" que não interrompe nenhuma funcionalidade existente.Por último, risco #3. Embora menor, este é provavelmente o "maior" risco dos 3. A Apple pode fazer uma série de alterações em
UIAlertController
uma atualização futura do iOS que pode atrapalhar ou quebrar o resultado desejado de usoUILabel.appearance
em sua subclasse. Testar o código em cada versão do iOS seria prudente. Provavelmente, o pior caso será que o “hack” pare de funcionar.