1

I'm trying to pass the data and got this error: 'subscript(_:)' is unavailable: cannot subscript String with an Int, use a String.Index instead. Here is my code:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell: CustomLoopsCell = beatTableView.dequeueReusableCell(withIdentifier: "firstLoopCell", for: indexPath) as! CustomLoopsCell
        
        let beatLoop = overtunePacks[indexPath.row]

        // On the lines which is down I'm getting this error
        let beatDesc = loopsDesc[indexPath.row]
        let beatProd = loopsProd[indexPath.row]
        let beatAudio = loopsAudio[indexPath.row] 
        let beatInst = loopsInst[indexPath.row]
        
        cell.loopNameLabel.text = beatDesc
        cell.producerLabel.text = beatProd
        cell.instrumentLabel.text = beatInst

Here is the code from another view controller, from where I'm passing the data:

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let vc = storyboard?.instantiateViewController(identifier: "BeatViewID") as? BeatPackViewController
    vc?.beatInfoCollectName = beatInfoCollect[indexPath.row].name
    vc?.beatProducerName = beatInfoCollect[indexPath.row].producer
    vc?.imageBeat = beatInfoCollect[indexPath.row].imagename
    vc?.loopsAudio = beatAudioCollect[indexPath.row].loopPath
    vc?.loopsDesc = beatAudioCollect[indexPath.row].name
    vc?.loopsInst = beatAudioCollect[indexPath.row].instrument
    vc?.loopsProd = beatAudioCollect[indexPath.row].producer
    self.navigationController?.pushViewController(vc!, animated: true)
}

Here is my variables in second view controller, where I'm passing data:

var loopsAudio = ""
    var loopsDesc = ""
    var loopsInst = ""
    var loopsProd = ""

Here is what I want to display:

struct BeatLoops: Decodable {
        let name: String
        let instrument: String
        let loopPath: String
        let producer: String
        
        var songURL : URL {
            let components = loopPath.components(separatedBy: ".")
            guard components.count == 2,
                  let url = Bundle.main.url(forResource: components[0], withExtension: components[1]) else { fatalError("Audio file is missing") }
            return url
        }
    }

I'm parsing this data and have instance: var beatAudioCollect = [BeatLoops]()

dextermikles
  • 107
  • 6
  • 2
    Did you check these related questions? https://stackoverflow.com/search?q=%5Bswift%5D+cannot+subscript+String+with+an+Int – Martin R Sep 08 '21 at 07:30
  • Yes, but there is no answer for my problem – dextermikles Sep 08 '21 at 07:32
  • 1
    You need to update your question include the declaration of the variables that are causing the problem. I would also suggest updating your question to include a [minimum, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) – Andrew Sep 08 '21 at 07:33
  • Check, I've updated – dextermikles Sep 08 '21 at 07:35
  • 2
    You probably want to get a value from an array by index rather than from a string (a single **character**) – vadian Sep 08 '21 at 07:39
  • Cant understand what you mean – dextermikles Sep 08 '21 at 07:44
  • For example If `loopsDesc` is `Foo` then you'll get `F` for indexPath.row 0, `o` for indexPath.row 1 and also `o` for indexPath.row 2. This is certainly not what you want. You might add the information what you want to display in the second view controller. It looks like a single object so another table view is not needed. – vadian Sep 08 '21 at 07:47
  • I want to display data from JSON, I will update the code now – dextermikles Sep 08 '21 at 07:55

2 Answers2

2

Seems that you are trying to get Substring from a loopsDesc String here

let beatDesc = loopsDesc[indexPath.row]
...
let beatInst = loopsInst[indexPath.row]

The point is that you can't just get String's characters using subscription index.

If you want to get a character from a String, you should get it's Substring with a specified range.

Like that:

let index = loopsDesc.index(loopsDesc.startIndex, offsetBy: 1)
let mySubstring = loopsDesc[..<index]

Or another way:

1 - add this extension to a String:

extension StringProtocol {
subscript(offset: Int) -> Character {
    self[index(startIndex, offsetBy: offset)]
  }
}

2 - use it like that

let input = "My String Here"
let char = input[3]
//or
let char = String(input[3])

Please see another stackoverflow question related to that.

But it's unsafe method and I would suggest to use another way to get params (for example store them in Array, not in String)

Raman Shyniauski
  • 392
  • 2
  • 13
0

Your design is wrong.

Extracting single characters from a string in a table view to be displayed in different rows makes no sense.

Actually you are passing two objects to the second view controller, an infoCollect object and an audioCollect object.

First of all rather than extracting all properties just pass the entire objects.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let vc = storyboard?.instantiateViewController(identifier: "BeatViewID") as! BeatPackViewController
    vc.infoCollect = beatInfoCollect[indexPath.row]
    vc.audioCollect = beatAudioCollect[indexPath.row]
    self.navigationController?.pushViewController(vc, animated: true)
}

By the way using multiple arrays as data source is strongly discouraged!.


In the second controller replace the String properties with

var infoCollect : Loop!
var audioCollect : BeatLoops!

If the structs are declared inside in first view controller you have to write

var infoCollect : BPLibraryViewController.Loop!
var audioCollect : BPLibraryViewController.BeatLoops!

Then remove the table view and add UILabels instead. In viewDidLoad assign the values for example

imageBeatLabel.text = infoCollect.name
loopsAudioLabel.text = audioCollect.loopPath
vadian
  • 274,689
  • 30
  • 353
  • 361
  • On this line: vc?.audioCollect = beatAudioCollect[indexPath.row] - I'm getting an error: Cannot assign value of type 'BPLibraryViewController.BeatLoops' to type 'BeatLoops' – dextermikles Sep 08 '21 at 08:31
  • You have to declare the proper matching type. I just guessed what it is. – vadian Sep 08 '21 at 11:39
  • Proper matching type, what do you mean? – dextermikles Sep 08 '21 at 12:16
  • Te proper type of `beatInfoCollect` and `beatAudioCollect` – vadian Sep 08 '21 at 12:20
  • Now they are: var beatInfoCollect = [Loop]() var beatAudioCollect = [BeatLoops]() – dextermikles Sep 08 '21 at 13:06
  • I'm getting an error: Value of type 'BPLibraryViewController.BeatLoops' has no member 'count' When I've tried this: func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return audioCollect.count } – dextermikles Sep 08 '21 at 13:45
  • Please read my answer. As I said, **remove the table view**. It's not needed. The data is static – vadian Sep 08 '21 at 13:56
  • But I need that it will be in table view, if I will remove what it will be? – dextermikles Sep 08 '21 at 14:01
  • According to your `didSelectRowAt` method you are going to display 7 (static) values in the second view controller. So replace the table view with 7 labels. – vadian Sep 08 '21 at 14:05
  • Not like this. At the first view controller I have a table view and there is 4 cells. And when I tap on each of them, it pass data to the second view controller using this methods. – dextermikles Sep 08 '21 at 14:16