1

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
} 
}

3 Answers3

3

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)
}
Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • The problem is that, for certain cells, i use custom UITableViewCells, some of which need to have their delegate declared in the same function `cellForRow AtIndexPath:` – Fayez Hellani May 19 '17 at 05:54
  • @FayezHellani See the edit. Assign the delegates in `// configure cell here`. – Sweeper May 19 '17 at 05:58
  • I only need to configure the `ScrollFeedCell`. Anw, I want to use this because I don't only have 3 types of custom cells, i nearly have 8. – Fayez Hellani May 19 '17 at 06:01
0

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.
}

//....
Yun CHEN
  • 6,450
  • 3
  • 30
  • 33
  • It is not really necessary, but it's inconvenient to have a huge amount of code to look through, when you have 8 types of cutom UITableViewCells – Fayez Hellani May 19 '17 at 06:01
  • Answer updated for your requirements. Just check the specific cell which have custom actions in if case. For others, just return it and do nothing. – Yun CHEN May 19 '17 at 06:04
0

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

Alfredo Meraz
  • 139
  • 1
  • 7