Value of type 'xxxxx.type' has no subscript

Help!

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TaskTableViewCell", for: indexPath)
        as! TasksTableViewCell
    
    
    
    let tasks = task[indexPath.row]
    cell.taskName?.text = tasks.title
    cell.taskPoints?.text = tasks.text
    
    return cell
}

Is task an array type?

No it's a struct

Well, in that case, how do you expect to access one of a list, which is what the code you have written does?

Have you created a list of tasks anywhere? Can you show some more code where you create the list?

import UIKit

struct task {

var taskName: String
var taskPoints: String

}

class TasksTableViewCell: UITableViewCell {

@IBOutlet weak var taskName: UILabel!
@IBOutlet weak var taskPoints: UILabel!

}

class addTaskTableViewController: UITableViewController {

var Task = [
    task(taskName: "Plant 1 tree", taskPoints: "100"),
    task(taskName: "Close all unused lights", taskPoints: "25"),
    task(taskName: "Recycle all recyclable trash", taskPoints: "25"),
]

let cellIdentifier = "TaskTableViewCell"

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "TaskTableViewCell", for: indexPath)
        as! TasksTableViewCell
    
    
    
    let tasks = Task[indexPath.row]
    cell.taskName?.text = tasks.taskName
    cell.taskPoints?.text = tasks.taskPoints
    
    return cell
}

This is my code, it might not be organized well. I'm new sorry.

This should be lowercase.

1 Like

No worries! On the bright side, you just learned first hand what motivates code conventions. If struct task was named according to Swift's convention of using UpperCamelCase for types, @Joanna_Carter wouldn't have has to ask what type Task is.

  • The names got you all mixed up. You were subscripting task (task[indexPath.row]), which was subscripting your struct task (which was incorrectly named)
    • which as a formal error because your struct doesn't define a static subscript operator,
    • but it's also a logical error, because you actually meant to be subscripting your array of tasks, which you called Task. That's an incorrect name, because:
      • it's UpperCamelCase (identifiers of values should be lowerCamelCase), and
      • it's singular, yet it was an array of a plurality of structs.
  • The "task" in taskName and taskPoints in struct Task are redundant. We know they belong to Task already.
  • Task points should be a numeric type, probably Int but possibly Double/Decimal (if you need fractional numbers of points).
  • You should format the task.points field according to the correct locale for the user.
import UIKit

struct Task {
    var taskName: String
    var taskPoints: Int
}

class TasksTableViewCell: UITableViewCell {
    @IBOutlet weak var taskName: UILabel!
    @IBOutlet weak var taskPoints: UILabel!
}

func formatQuantity(_ i: Int) -> String {
    let nf = NumberFormatter() // Cache this if necessary for performance
    nf.usesGroupingSeparator = true
    nf.locale = Locale.current
    return nf.string(from: NSNumber(value: i)!
}

class AddTaskTableViewController: UITableViewController { // Make sure you update the name in your story board to be capitalized
    var tasks = [
        Task(name: "Plant a tree", points: 100),
        task(name: "Turn off all unused lights", points: 25),
        task(name: "Recycle all the recyclables", points: 25),
    ]

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "TaskTableViewCell", for: indexPath)
            as! TasksTableViewCell
        
        let tasks = tasks[indexPath.row]
        cell.taskName?.text = tasks.name
        cell.taskPoints?.text = formatQuantity(tasks.points)
        
        return cell
    }
}

P.S. In "Closing the lights" it's a regionalism used by some Francophone English speakers, such as in Quebec, but the correct phrase it "Turn off all unused lights".

P.P.S. If it's recyclable, then it's not trash. Idk what the correct term is, but around here (Toronto, Canada) we say "Recycle all recyclables".

3 Likes

Just to supplement Alexander's post, here's a version of the code that is properly type safe, complete and properly separated out to make it easier to debug and reuse.

//  Task.swift

struct Task
{
  let name: String
  
  let points: Int
}

Do not repeat the name of the struct in the names of the properties; it makes it harder to read

//  TaskTableViewCell.swift

import UIKit

class TaskTableViewCell : UITableViewCell
{
  @IBOutlet private weak var nameLabel: UILabel!
  
  @IBOutlet private weak var pointsLabel: UILabel!
  
  static let rowHeight: CGFloat = 90.0
  
  var task: Task?
  {
    didSet
    {
      guard let task = task else
      {
        return
      }
      
      nameLabel.text = task.name
       
      pointsLabel.text = "\(task.points)"
    }
  }
}

To avoid confusion, do not name the UI components without specifying its type.

Adding a Task property to the cell means you can change both the contents of the Task struct and the components in the cell without having to rewrite any of the code in the view controller.

//  TaskTableViewController.swift

import UIKit

class TaskTableViewController: UITableViewController
{
  lazy var tasks = [
                     Task(name: "Plant 1 tree", points: 100),
                     Task(name: "Turn off all unused lights", points: 25),
                     Task(name: "Recycle all recyclable trash", points: 25),
                   ]
  
  override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
  {
    return tasks.count
  }
  
  override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
  {
    return TaskTableViewCell.rowHeight
  }
  
  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
  {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "TaskCell", for: indexPath) as? TaskTableViewCell else
    {
      return UITableViewCell()
    }
    
    cell.task = tasks[indexPath.row]
    
    return cell
  }
}

Note the dequeued cell is properly checked rather than allowing the exclamation mark to possibly raise a nil exception and crash the app; instead a default blank cell is provided as a fallback.

Ah! Problem solved, thanks so much people!

Merry Christmas BTW

Arthur

Just a quick question though, when creating task.swift as a brand new cocoa touch class, what subclass should it belong to?

Thanks for the terminology advices, it will be fixed.
Thank you

Merry Christmas

Arthur

Task is defined as a struct, not a class; therefore it cannot derive from another class. I suggest you read the Swift Programming Language book, available from the Apple Books store.

Ok thank you :smiley: