Programação iOS

Boa noite,

Mais um problema: table views. Não é a primeira vez que uso mas por alguma razão não me está a aparecer nada nesta...

Código:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
        return 1
    }
   
    public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
        let cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "Cell")
       
        cell.textLabel?.text = "hi!"
       
        return cell
    }
}

Era suposto ver hi! na primeira celula mas não aparece nada. Alguma dica?
 
Boas,
Tens de especificar onde está a celula na tabela através do index path.

Experimenta algo deste género:
Código:
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
 
Não tem. O problema aí não é a falta do indexPath. O problema é, quase de certeza, a falta do data source para a table view.

Basicamente o que está aqui, no parágrafo: Connecting the DataSource and Delegate


Já agora @fUrian, uma correção ao que disseste. Esse for: indexPath não é para dizer onde encontrar a cell, visto esse conceito não existir numa dynamic table view. Esse for é usado para questões visuais e para ser um método diferente do dequeue sem indexPath mais antigo. Ao saber que a cell é para a row/section x o sistema consegue fazer o resize automatico do que for preciso. Para além disso esse método devolve sempre uma cell enquanto que o método mais antigo devolvia simplesmente nil caso não exista.
 
Última edição:
Boa noite,

Está a acontecer outra vez (parecido). Quando mudo de determinada view para outra, a simulação crascha e termina sessão.

Não acusa nenhum erro nem warning ao compilar nem aparece nenhuma mensagem de erro quando crasha. Ando aqui às voltas a tentar perceber o que fiz mal mas não me salta nada a vista. Há algum sitio no xcode que eu possa consultar o porquê do crash?
 
Cheguei à conclusão que o erro está aqui mas não sei porquê. Uma ajudinha pf?

Código:
let mapViewController = segue.destination as! MapViewController

O MapViewController.swift só tem isto:

Código:
class MapViewController: UIViewController {
   
    var activePlace = -1

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}
 
@elfo106, para te tentar colocar no caminho certo sem te dar a resposta directamente, experimenta trocar o código do teu primeiro bloco por este:

Código:
let mapViewController = segue.destination
print(type(of:mapViewController))

Tenta descobrir qual era o problema a partir daí.
 
Olá, obrigado pela ajuda mas entretanto já resolvi o problema. De qualquer forma fiquei curioso sobre essa dica e logo à noite vou testar isso :) Já agora aproveito para perguntar o porquê de isto ter acontecido.

Quando se seleciona uma view na storyboard, no painel da direita há um campo para indicar a que class essa view pertence. Eu pensava que podia ser alguma gralha no nome que o estivesse a crashar...mas não...o nome estava certo. Imediatamente por baixo desse campo há um outro (não tenho a certeza mas acho que se chama "module"). Cliquei e sem escrever nada dei enter. (vi isto na net claro) E ficou resolvido. Fiquei é sem perceber porquê que desta tive que fazer este procedimento..
 
Assim sendo isso era um qualquer bug do Xcode, de alguma forma estava a compilar mal o Storyboard. A minha ideia era que visses que a classe estava realmente mal, se o que ali coloquei fizesse print de "UIViewController" vias que não era um "MapViewController" e vias onde estava o problema. Como fazes:

Código:
as! MapViewController

Se a classe não for um MapViewController a app vai rebentar. Apesar de não ser algo extremamente importante nos segues, eu pessoalmente aconselho menos o uso de conversōes forçadas e mais o uso de programação defensiva. Ter uma app a rebentar não fica muito bem :p

por exemplo:
Código:
guard let mapViewController = segue.destination as? MapViewController else {
      //Aqui tratas a eventualidade de o mapViewController não ser um MapViewController, o downside desta abordagem é que o guard tem que saltar fora, pode não ser o melhor em todo o lado
     return
}
// aqui já sabes que mapViewController tem o tipo que querias e podes usá-lo livremente

ou:
Código:
if segue.destination is MapViewController {
      // Sabes que é
} else {
    // sabes que não é
}

Novamente, os segues são um caso especial e menos problemáticos. A não ser, claro, que os estejas a criar programaticamente, aí são bem mais inseguros. Fora os segues, programação defensiva all the way!
 
Algo assim?

Código:
if segue.destination is MapViewController {
      // Sabes que é
      let mapViewController = segue.destination

} else {
    // sabes que não é
    Print("erro MapViewController não existe")
}

O else só corre se eu me enganar a escrever o nome das classes. Não ha nada que o utilizador possa fazer na aplicação que provoque este erro, logo seria detetado durante a simulação.
 
@elfo106, nesse caso específico já não aconselhava esse if. Funcionaria sem problemas e podes fazer como disseste mas, na minha perspectiva, tens duas maneiras mais elegantes de juntar o primeiro if com o assign dentro dele:

Código:
guard let mapViewController = segue.destination as? MapViewController else {
     return
}
// A partir daqui sabes que o mapViewController existe e é obrigatoriamente um MapViewController

ou:
Código:
if let mapViewController = segue.destination as? MapViewController {

// Aqui dentro sabes que o mapViewController existe e é obrigatoriamente um MapViewController 

} else {

}

//Aqui já não conheces o mapViewController, ele apenas está vivo dentro do if

As duas maiores diferenças de guard let... e if let... são:

No guard o assign que fazes é válido para tudo o que esteja depois do Guard
No if a variável apenas existe dentro do if

O guard obriga-te a um return no caso de erro (no else)
O if procede normalmente
 
Boa noite,

Mais um erro...

ERROR /BuildRoot/Library/Caches/com.apple.xbs/Sources/VectorKit_Sim/VectorKit-1230.31.8.23.3/GeoGL/GeoGL/GLCoreContext.cpp 1763: InfoLog SolidRibbonShader:
ERROR /BuildRoot/Library/Caches/com.apple.xbs/Sources/VectorKit_Sim/VectorKit-1230.31.8.23.3/GeoGL/GeoGL/GLCoreContext.cpp 1764: WARNING: Output of vertex shader 'v_gradient' not read by fragment shader
 
Estou com outra dúvida se não se importam...

Código:
places.append(["name":title,"lat":String(newCoordinate.latitude),"lon":String(newCoordinate.longitude)])
               
                print(places)
            })

places é um dicionário declarado e usado numa tableview noutra view. Como é que eu posso fazer o append sem declarar o places como global?
 
Assumindo que estás a passar do View controller onde tens e places para outro e que queres os places nesse outro, podes passar o places no método prepareForSegue.
 
Olá, isso levanta-me duas questões, uma genérica e outra mais específica:

1 - O prepareForSegue não é apenas chamado quando há uma transição "visual" de uma view para outra? Imaginemos que eu tenho uma table view que mostra o conteúdo desse tal places. Para além dessa view tenho uma segunda view onde faço os appends. Posso fazer vários appends seguidos sem ir para a table view que quando voltar à tableview vou ver os items todos que foram adicionados ao places?

2 - Um outro caso concreto:

Código:
CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error)
                in
               
                if error != nil{
                    print(error)
                }
                else{
                    (...)
               
                let annotation = MKPointAnnotation()
                annotation.coordinate = newCoordinate
                annotation.title = title
                self.map.addAnnotation(annotation)
               
                places.append(["name":title,"lat":String(newCoordinate.latitude),"lon":String(newCoordinate.longitude)])
            })

Apesar de ter passado este places através do prepareForSegue, dentro do reverseGeocodeLocation essa variável não é reconhecida. Como posso contornar isso?
 
Back
Topo