Swift - Type Casting - ios

I am building a custom UITableView with custom cells.
Each of the custom cells are a subclass of FormItemTableViewCell
I am attempting to populate the cell data in cellForRowAtIndexPath
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = FormItemTableViewCell();
if(indexPath.row == 1){
cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
} else {
cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
}
cell.questionLabel.text = "What is the meaning of life?";
return cell
}
How do I access the elements in the subclass?
For example: TwoOptionTableViewCell has a segControl
while the OneTextFieldTableViewCell has a answerTextField

There are some decent answers in this question but most of them have one bad thing in common, they force unwrapped optionals, which you should avoid as much as you can (pretty much the only acceptable place to use them is in IBOutlets)
This is what I think is the best way to handle this:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCellWithIdentifier("Identifier", forIndexPath: indexPath) as? FormItemTableViewCell else {
fatalError("Cell is not of kind FormItemTableViewCell")
}
switch cell {
case let cell as TwoOptionTableViewCell where indexPath.row == 1:
// Configure cell, which is an object of class TwoOptionTableViewCell, but only when we are in row 1
break
case let cell as TwoOptionTableViewCell:
// Configure cell, which is an object of class TwoOptionTableViewCell, when the row is anything but 1
break
case let cell as OneTextFieldTableViewCell:
// Configure cell, which is an object of class OneTextFieldTableViewCell
break
case _: print("The cell \(cell) didn't match any patterns: \(indexPath)")
}
cell.questionLabel.text = "What is the meaning of life?";
return cell
}
Now let me walk you through the reasons I think it's the best way.
First of all, it doesn't force unwraps any optionals, everything is unwrapped nicely in the switch case.
It dequeues your cell from the table (something you should always do) and makes sure it's a subclass of FormItemTableViewCell, otherwise it throws a fatal error.
By using a switch case, it casts cell into the class you need, and at the same time it checks if it's the index path you want. So if you want to share some logic in different rows that share a class, you can compare indexPath.row to multiple values. If you don't use the where clause, it will use the same logic in all places where it finds a cell with that class.
Do note that you will need to add some logic to get the desired identifier depending on the row.

You can use one of the two approaches:
1) The best way:
if(indexPath.row == 1) {
let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
// the type of cell is TwoOptionTableViewCell. Configure it here.
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
// the type of cell is TwoOptionTableViewCell. Configure it here.
return cell
}
2) If you declare cell just once, as a superclass, then you have to downcast it like this.
var cell: FormItemTableViewCell
cell = ... // dequeue and assign the cell like you do in your code.
if let twoOptionCell = cell as? TwoOptionTableViewCell
{
// configure twoOptionCell
}
else if let oneTextFieldCell = cell as? OneTextFieldTableViewCell
{
// configure oneTextFieldCell
}
return cell
This is more verbose, once you add the code to dequeue the cell. So I personally prefer and recommend the first approach.

If I understand correctly, you want to keep main declaration of cell as FormItemTableViewCell to access common properties.
You can create a new variable and assign it the casted version.
Do your stuff with this instance as this is a class object it will point to same reference.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = FormItemTableViewCell();
// this can be replaced with below line as I don't see the purpose of creating an instance here while you use dequeue below.
// var cell: FormItemTableViewCell!
if(indexPath.row == 1){
cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath);
let tempCell = cell as! TwoOptionTableViewCell;
// access members of TwoOptionTableViewCell on tempCell
tempCell.segControl.someProperty = 0;
} else {
cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath);
let tempCell = cell as! OneTextFieldTableViewCell;
// access members of OneTextFieldTableViewCell on tempCell
tempCell.answerTextField.text = "42";
}
cell.questionLabel.text = "What is the meaning of life?";
return cell
}

You're going to have to conditionally cast them in that case. I like using Enums for Rows/Sections instead of == 1 (depending on how your TableView is setup), but basically you'll want to do the following:
if indexPath.row == 1 {
let cell = tableView.dequeueReusableCellWithIdentifier(twoOptionCellIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
// Note that we cast the cell to TwoOptionTableViewCell
// access `segControl` here
return cell
} else {
let cell = tableView.dequeueReusableCellWithIdentifier(oneTextFieldCellIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
// This cell we cast to OneTextFieldTableViewCell.
// access `answerTextField` here
return cell
}
What you were doing was defining the cell as FormItemTableViewCell, so subsequent accesses would only know it in that form even though you explicitly cast it to a subclass during assignment.
As a side-note, you don't have to assign to the var as you did there, what you could do is let cell: FormItemTableViewCell. Then in the if-statements you could define new cells of the subclasses, operate on them, and then assign back to your original cell and then return that. This is useful if you're going to be performing the same operations on both cell types after the if statements (such as setting a background colour or something, regardless of which subclass you have).
Here is my favourite way of handling this situation:
enum CellTypes {
case TwoOption, OneTextField
init(row: Int) {
if row == 1 {
self = .TwoOption
} else {
self = .OneTextField
}
}
var reuseIdentifier: String {
switch self {
case .TwoOption: return "twoOptionReuseIdentifier"
case .OneTextField: return "oneTextFieldReuseIdentifier"
}
}
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: FormItemTableViewCell
let cellType = CellTypes(row: indexPath.row)
switch cellType {
case .TwoOption:
let twoOptionCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! TwoOptionTableViewCell
// do stuff with the `segControl`
cell = twoOptionCell
case .OneTextField:
let textFieldCell = tableView.dequeueReusableCellWithIdentifier(cellType.reuseIdentifier, forIndexPath: indexPath) as! OneTextFieldTableViewCell
// do stuff with the `answerTextField`
cell = textFieldCell
}
// Here do something regardless of which CellType it is:
cell.questionLabel.text = "What is the meaning of life?"
return cell
}

Related

convert String content to UITableViewCell type in swift

Can you convert the content of a Swift 3 String into a type through a specific function? I'll include an example:
I've declared multiple UITableViewCell classes as follows:
class ScrollFeedCell : UITableViewCell {...}
class AdCell : UITableViewCell {...}
class MovieCell : UITableViewCell {...}
I want to declare the conversion function, in my view controller, as follows:
func convert(String) -> Any {}
Then I want to use the following:
class TableView : UITableViewController {
let typeArray = [String]
override func viewDidLoad() {
//add a huge ton of strings into the typeArray
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = UITableViewCell()
let c = typeArray[indexPath.section]
if c == "ScrollFeddCell" || c == "AdCell" || c == "MovieCell" {
cell = tableView.dequeueReusableCell(withIdentifier: content[indexPath.section], for: indexPath) as! convert(c)
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "CategoryScrollFeed_Cell", for: indexPath)
}
return cell
}
}
I do not think this is possible. Even if it is somehow possible, I think it is going to involve lots of dirty tricks which is not really worth it in this situation.
In fact, the only place you used your imaginary convert method is here:
cell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! convert(c)
^^^^^^^^^^
Why do you want to cast it to the right type? Since this is very dynamic, the compiler can't know what members will the type returned by convert have. Basically, too dynamic. It is not useful to cast it to the right type here.
The enclosing method returns a UITableViewCell anyway, so you can just return the return value of dequeueResuableCell without the compiler complaining.
"But I want to configure the cell after dequeuing it though..." you might say.
Well, you are going to configure a ScrollFeedCell in a different way from a MovieCell, right? So you can't just write all the configuration code after this line:
cell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! convert(c)
You still have to write an if statement and check whether the cell is a MovieCell, ScrollFeedCell or AdCell. So why not delete the above line and do this instead:
if c == "ScrollFeedCell" {
let scrollFeedCell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! ScrollFeedCell
// configure cell here
cell = scrollFeedCell
} else if c == "AdCell" {
let adCell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! AdCell
// configure cell here
cell = adCell
} else if c == "MovieCell" {
let movieCell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! MovieCell
// configure cell here
cell = movieCell
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "CategoryScrollFeed_Cell", for: indexPath)
}
Edit:
Try this:
if c == "ScrollFeedCell" {
let scrollFeedCell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath) as! ScrollFeedCell
scrollFeedCell.delegate = self
cell = scrollFeedCell
} else if c == "AdCell" || c == "MovieCell" { // add your other cell types here.
cell = tableView.dequeueReusableCell(withIdentifier:
content[indexPath.section], for: indexPath)
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "CategoryScrollFeed_Cell", for: indexPath)
}
Please consider what you want to do is necessary or not. Why you want to convert them to specific cell type? It will work just keep the cell as UITableViewCell and return it. If you have specific actions for different cells, you should separate the if cases:
if c == "ScrollFeddCell" {
cell = tableView.dequeueReusableCell(withIdentifier: c, for: indexPath) as! ScrollFeddCell
//cell.doSomethingForScorll()
}
else {
cell = tableView.dequeueReusableCell(withIdentifier: c, for: indexPath)
//do nothing for common cells.
}
//....
A little late, but for those looking for an answer:
I know what you want, and I agree with your need.
In my case, I need to do this because in my app, I not only receive the data from the server, but ALSO the layout of such data inside the cell. So far, I haven't been able to find a solution. In your case, it seems a little easier:
// 1. Create a protocol with the configuring method
protocol configureCellProtocol
{
func configure(cell:MyData)
}
// 2. Add this protocol to the 8 classes derived from UITableViewCell that define your cells
// 3. Cast the reusable cell to this protocol: (note that you have to do a double cast,
// both to configureCellProtocol and UITableViewCell, (that's what the & is for) otherwise,
// you won't be able to return the configured cell
let thisCell=tableView.dequeReusableCell(
withReuseIdentifier: cellClass, for: indexPath) as! UITableViewCell & configureCellProtocol
// 4. then you can call the method like this:
thisCell.configure(cell:configurationData)
// which in turn will call the specific method in each class. Then you have to define the configure
// method in each class, otherwise you'll get a crash at runtime. Do what you need to configure
// your cells in each class in this method
//
in step 3, cellClass is a String, which in turn is the class name that you register. In your case, you would have to select it from an array according to the criteria that makes every cell different

How can I use an if statement to set a type of variable to a specific type of custom tableCell?

I have three different types of custom UITableCells. I have an if statement that sets them up:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if somePosts[indexPath.row].typeOfPost == .linkPost {
let cell: LinkTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .picturePost {
let cell: PictureTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .textPost {
let cell: TextTableViewCell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell
} else {
print("Type of post is not link, picture, or text")
}
}
Each of the custom cells has similar labels such as title and time. I would like to set these labels using the same line of code, such as:
cell.titleLabel.text = "Some title here"
However, in this example, I get an error saying I am using an unresolved identifier "cell," obviously because my variables are being declared non-globally. Is there a way around this since swift is strongly typed? Thanks!
Make a protocol that your TableViewCell classes extend, and store cell as a variable of that type.
protocol MyTableViewCell {
var titleLabel: UILabel { get }
// ...
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let identifier: String
switch somePosts[indexPath.row].typeOfPost {
case .linkPost: identifier = "linkTableViewCell"
case .picturePost: identifier = "pictureTableViewCell"
case .textPost: identifier = "textTableViewCell"
default: fatalError("Type of post is not link, picture, or text")
}
guard let cell = self.tableView.dequeueReusableCell(withIdentifier: identifier) as? MyTableViewCell else {
fatalError("Cell isn't castable to MyTableViewCell")
}
cell.titleLabel.text = "Some title here"
// ...
}
You have three basic solutions.
Repeat cell.text = ... inside each block. But this isn't what you really want as stated in your question.
Have your three custom cell classes all extend a common base class. Have this base class define any common properties.
Define a protocol with the common properties and have each of your custom cell classes conform to the protocol.
For options 2 and 3 you would declare a variable of the base/protocol type before the first if statement. Then after the whole if/else block, you can assign any of the common properties.
If you need to update any cell type specific properties, you can do that inside the appropriate block as well.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell: BaseTableViewCell?
if somePosts[indexPath.row].typeOfPost == .linkPost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .picturePost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .textPost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell
} else {
print("Type of post is not link, picture, or text")
}
if let cell = cell {
cell.commonProperty = ...
return cell
} else {
return nil // this shouldn't happen but if it does, you have a bug to fix
}
}
If the subclasses each have their own titleLabel property, you will need to make them all conform to a protocol. Let's call it ConfigurableCell.
protocol ConfigurableCell {
var titleLabel: UILabel { get set }
}
Then, you can initialize your cells all the same way, but declare them as a ConfigurableCell:
var cell: ConfigurableCell? = nil // not set yet
if somePosts[indexPath.row].typeOfPost == .linkPost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "linkTableViewCell") as! LinkTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .picturePost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "pictureTableViewCell") as! PictureTableViewCell
} else if somePosts[indexPath.row].typeOfPost == .textPost {
cell = self.tableView.dequeueReusableCell(withIdentifier: "textTableViewCell") as! TextTableViewCell
}
guard let cell = cell else {
// how to handle this error case is up to you
print("Type of post is not link, picture, or text")
return UITableViewCell()
}
// now, cell is a ConfigurableCell with a titleLabel property, regardless of class
cell.titleLabel.text = "Some title"
Of course, UITableViewCell does have a built-in textLabel property, which you could try to utilize in your cell classes, and then a protocol wouldn't be necessary, because the property is in UITableViewCell.

Implementing two UITableViews with the same custom cell for reuse

I have currently have two UITableViews populated with contacts for the app. I have one for simply viewing them and editing/deleting and one for searching/picking contacts from a list. However, I'm getting a returned nil value when trying to use the same custom class cell for both UITableViews.
These are my two cellForRowAtIndexPath functions.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("SecondCell") as! ContactCell
let item = contacts[indexPath.row]
cell.meetupLabel?.text = item.fullName
return cell
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCellWithIdentifier("FirstCell") as! ContactCell
let item = contacts[indexPath.row]
cell.label?.text = item.fullName
return cell
}
If the table did not have a cell named FirstCell or SecondCell, the dequeueReusableCellWithIdentifier(_:) method will return nil, and you will need to construct the cell yourself.
// no don't do this.
let cell: ContactCell
if let c = tableView.dequeueReusableCell(withIdentifier: "FirstCell") as? ContactCell {
cell = c
} else {
cell = ContactCell(style: .default, reuseIdentifier: "FirstCell")
}
You should use dequeueReusableCell(withIdentifier:for:), which was introduced in iOS 6, if you would like UIKit to construct the cell for you:
// swift 3
let cell = tableView.dequeueReusableCell(withIdentifier: "FirstCell",
for: indexPath) as! ContactCell
// swift 2
let cell = tableView.dequeueReusableCellWithIdentifier("FirstCell",
forIndexPath: indexPath) as! ContactCell
...
Also, check if you have given the correct reuse-identifiers to the cells correctly in the interface builder.
As you said you are getting nil, my quick guess is that you haven't registered the cell at some point, runs earlier than this cell event. Look at this thread on how to register cell.

swift variable type won't change after downcast if the variable has been declared?

I intended to downcast a UITableViewCell to different subclasses based on which section it is in.
Suppose a subclass of UITableViewCell is CellOne and it has a var nameLabel. In one case, I downcast (as!) the UITableViewCell returned by dequeueReusableCellWithIdentifier(_:_:) to CellOne and assigned it to cell, a variable declared as var cell = UITableViewCell() outside the switch block.
But after that, cell can't access nameLabel that is held by CellOne instance. I got the error message: "Value of type 'UITableViewCell' has no member nameLabel".
So it seems cell has not been downcasted to UITableViewCell's subclass.
Is there any way that cell can access nameLabel (after declared outside the block)? Can a variable be downcasted to another type by assigning a subclass instance to it after it has been declared?
Thank you very much for your time.
Here is my code:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = UITableViewCell()
switch indexPath.section {
case 0:
cell = tableView.dequeueReusableCellWithIdentifier("cellOne", forIndexPath: indexPath) as! CellOne
cell.nameLabel.text = "one" // Error: Value of type 'UITableViewCell' has no member 'nameLabel'
case 1:
cell = tableView.dequeueReusableCellWithIdentifier("cellTwo", forIndexPath: indexPath) as! CellTwo
...... // Other cases
}
return cell
}
And code for CellOne:
class CellOne: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
......
}
The problem is where you declared the variable cell you specifically said that its a UITableViewCell,so you will have issue to downcast it as yourCustomCell.
change this :
var cell = UITableViewCell()
Based on your comment you want to use multiple custom cells
I think you should declare those customs cells within the case code block
switch indexPath.section
{
case 0:
let cell = tableView.dequeueReusableCellWithIdentifier("cellOne", forIndexPath: indexPath) as! CellOne
cell.nameLabel.text = "one"
case 1:
let secondCell = tableView.dequeueReusableCellWithIdentifier("cellTwo", forIndexPath: indexPath) as! CellTwo
// do whatever you want
}
I find it's better to make your cells more generic to they can work in more than one 'section'. ie. instead of 'CellOne' create your cell as 'NameCell' which can be used across all sections of your table.
Cells should be reusable.
let nameCell = tableView.dequeueReusableCellWithIdentifier("nameCell") as! NameCell
switch indexPath.section{
case 0:
nameCell.nameLabel.text = "name1"
break
case 1:
nameCell.nameLabel.text = "name2"
break
...
default:
...
}

reloadRowsAtIndexPaths doesn't update my cell data

I have a UITableView in my ViewController.
One of the cell could be tap into another TableViewController to allow select a value.
I want to update my cell after back from the callee ViewController.
right now, i could pass back the selected value by delegate.
However, i tried following way, none of them works.
self.mainTable.reloadData()
dispatch_async(dispatch_get_main_queue()) {
self.mainTable.reloadData()
}
self.mainTable.beginUpdates()
self.mainTable.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.None)
self.mainTable.endUpdates()
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
was called and executed without error.
but the UI just doesn't change
here is the way I update value in cellForRowAtIndexPath
if let currentCell = tableView.cellForRowAtIndexPath(indexPath) as UITableViewCell! {
currentCell.textLabel?.text = address
return currentCell
}
Here is my cellForRowAtIndexPath -
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let id = "Cell"
println(indexPath)
if indexPath.row == 1 {
var cell = tableView.dequeueReusableCellWithIdentifier(id) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: id)
cell?.contentMode = UIViewContentMode.Center
cell?.selectionStyle = UITableViewCellSelectionStyle.None
cell?.contentView.addSubview(mapView!)
}
return cell!
}else{
let cell = UITableViewCell()
cell.textLabel?.text = self.address
return cell
}
}
Here is the delegate method -
func passBackSelectedAddress(address: String) {
self.address = address
var indexPath = NSIndexPath(forRow: 0, inSection: 0)
self.mainTable.beginUpdates()
self.mainTable.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
self.mainTable.endUpdates()
}
My fix:
After more debug, i find the cause,
the self.address value is updated in delegate, however it roll back to previous value in cellForRowAtIndexPath.
I change the property to a static property, then resolve the problem.
I'm not sure what's wrong with instance property, and why it reverses back.
static var _address:String = ""
It seems like you're trying to grab a cell from the UITableView and then update the textLabel value that way. However, UITableView and UITableViewCell are not meant to be updated in this way. Instead, store the value of address in your class and update this value when the delegate calls back into your class. If cellForRowAtIndexPath constructs the UITableViewCell with the value of self.address, calling mainTable.reloadData() after should update the cell to the new value.
For example:
var address: String
func delegateCompleted(address: String) {
self.address = address
self.mainTable.reloadData()
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(<your identifier>)
if (indexPath == <your address cell indexPath>) {
let textLabel = <get your textLabel from the cell>
textLabel?.text = self.address
}
return cell
}
Your cellForRowAtIndexPath has some problems -
You are using the same re-use identifier for different types of cell (one with a map, one without)
When you allocate the table view cell for the other row, you don't include the re-use identifier.
You have no way of referring to the map view that you are adding after the method exits because you don't keep a reference.
If you are using a storyboard then you should create the appropriate prototype cells and subclass(es) and assign the relevant cell reuse ids. If you aren't then I suggest you create a cell subclass and register the classes against the reuse identifiers. Your cellForRowAtIndexPath will then look something like -
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var returnCell:UITableViewCell
if indexPath.row == 1 {
var myMapCell = tableView.dequeueReusableCellWithIdentifier("mapCell", forIndexPath:indexPath) as MYMapCell
myMapCell.contentMode = UIViewContentMode.Center
myMapCell.selectionStyle = UITableViewCellSelectionStyle.None
// Set the properties for a map view in the cell rather than assigning adding an existing map view
returnCell=myMapCell
}else{
returnCell = tableView.dequeueReusableCellWithIdentifier("addressCell", forIndexPath:indexPath)
returnCell.textLabel?.text = self.address
}
return returnCell;
}

Resources