1

I have following code in which I wand to load images. But whenever I Run the code other fields in collection are found empty and only one image is found in all collection data, & The following error is generated. IndexOutOfRangeException: Index was outside the bounds of the array. (wrapper stelemref) System.Object.virt_stelemref_class_small_idepth(intptr,object)

Below is my code :

[System.Serializable]
public class CollectionDataClass
{
    public string name;
    public string id;
    public string thumbnail;
    public Texture2D collectionImage;
}

[System.Serializable]
public class DataClass
{
    [SerializeField] public CollectionDataClass[] collectionDataClass;
}

[SerializeField] private DataClass[] DataClassArray;

public IEnumerator BookCatogary(string reqParameter)
{
    BookCatogaryBodyClass BookCatogryClass = new BookCatogaryBodyClass(reqParameter);
    string json = JsonConvert.SerializeObject(BookCatogryClass);
    Debug.Log("==========================>" + json);

    var req = new UnityWebRequest(bookCategaryAPI, "POST");
    byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);

    req.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
    req.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
    req.SetRequestHeader("Content-Type", "application/json");

    yield return req.SendWebRequest();

    if (req.isNetworkError)
    {
        Debug.Log("Error While Sending: " + req.error);
    }

    else
    {
        Debug.Log("Received: " + req.downloadHandler.text);
        string temp = req.downloadHandler.text;
        bookCatogaryObject = JsonConvert.DeserializeObject<BookCatogaryReceivedDataClass>(temp);
        catogaryCount = bookCatogaryObject.Data.Rows.Count;

        GetCatogariesName(catogaryCount);
        GenerateCollectionData();
    }
}


public void GenerateCollectionData()
{
    DataClassArray = new DataClass[bookCatogaryObject.Data.Rows.Count];

    for (int i = 0; i <= bookCatogaryObject.Data.Rows.Count; i++)
    {
        DataClassArray[i] = new DataClass();
        DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];

        for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
        {
            DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();

            DataClassArray[i].collectionDataClass[m].name = bookCatogaryObject.Data.Rows[i].String[m].CollectionTitle;
            DataClassArray[i].collectionDataClass[m].id = bookCatogaryObject.Data.Rows[i].String[m].Id;
            DataClassArray[i].collectionDataClass[m].thumbnail = bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail;
            StartCoroutine(DownloadImage(mediaUrl: DataClassArray[i].collectionDataClass[m].thumbnail , bookCatogaryObject.Data.Rows[i].String.Count));
        }
    }
}

IEnumerator DownloadImage(string mediaUrl, int count)
{
    UnityWebRequest request = UnityWebRequestTexture.GetTexture(mediaUrl);
    yield return request.SendWebRequest();
    if (request.isNetworkError || request.isHttpError)
        Debug.Log(request.error);
    else
    {
        //collectionImage = ((DownloadHandlerTexture)request.downloadHandler).texture;
        //collectionImageContainer[count] = collectionImage;
        for (int i = 0; i <= bookCatogaryObject.Data.Rows.Count; i++)
        {
            DataClassArray[i] = new DataClass();
            DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];

            for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
            {
                DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();
                DataClassArray[i].collectionDataClass[m].collectionImage = ((DownloadHandlerTexture)request.downloadHandler).texture;
            }
        }
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
Omkar P
  • 29
  • 5
  • You sure that’s all the relevant code? Where is bookcategoryObject defined? – BugFinder Jun 20 '22 at 11:14
  • @BugFinder bookcategoryObject is json response which on receiving I'm as a class. I ll update the code wait – Omkar P Jun 20 '22 at 11:20
  • At no point on that code do you declare or populate it. – BugFinder Jun 20 '22 at 11:22
  • @BugFinder First I'm trying to Deserilize the data from server then Im calling The "GenerateCollectionData" method in coroutine itself. – Omkar P Jun 20 '22 at 11:25
  • @BugFinder Once the json response is deserilized I populate my my custome objects with received json response in "GenerateCollectionsData" – Omkar P Jun 20 '22 at 11:28
  • You could simplify your code a lot and make it more readable by using locals. `var dc = new CollectionDataClass(); DataClassArray[i].collectionDataClass[m] = dc; dc.name = ...; dc.id = ...; dc.thumbnail = ...;` – Olivier Jacot-Descombes Jun 20 '22 at 12:16
  • @OlivierJacot-Descombes Sure Sir I ll do the same and upload the new one. – Omkar P Jun 20 '22 at 12:22

2 Answers2

1

This is not an answer to your question. I just wanted to show you how you can simplify code by using temp locals and object initializers. It also makes the code more efficient because it eliminates repeated indexing and member accesses. But more importantly, it makes the code more readable.

public async void GenerateCollectionData()
{
    var rows = bookCatogaryObject.Data.Rows;
    DataClassArray = new DataClass[rows.Count];

    for (int i = 0; i < rows.Count; i++) {
        var currentString = rows[i].String;
        var dc = new DataClass {
            collectionDataClass = new CollectionDataClass[currentString.Count]
        };
        DataClassArray[i] = dc;

        for (int m = 0; m < currentString.Count; m++) {
            var collection = currentString[m];
            dc.collectionDataClass[m] = new CollectionDataClass {
                name = collection.CollectionTitle,
                id = collection.Id,
                thumbnail = collection.CollectionThumbnail,
                collectionImage = await GetImage(collection.CollectionThumbnail)
            };
        }
    }
}
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
0

So finally I found the answer to above question, instead of using coroutines I used async Task to return downloaded texture to GenerateCollectionData() method. Below is code for reference :

public async void GenerateCollectionData()
{
    DataClassArray = new DataClass[bookCatogaryObject.Data.Rows.Count];

    for (int i = 0; i < bookCatogaryObject.Data.Rows.Count; i++)
    {
        DataClassArray[i] = new DataClass();
        DataClassArray[i].collectionDataClass = new CollectionDataClass[bookCatogaryObject.Data.Rows[i].String.Count];

        for (int m = 0; m < bookCatogaryObject.Data.Rows[i].String.Count; m++)
        {
            DataClassArray[i].collectionDataClass[m] = new CollectionDataClass();

            DataClassArray[i].collectionDataClass[m].name = bookCatogaryObject.Data.Rows[i].String[m].CollectionTitle;
            DataClassArray[i].collectionDataClass[m].id = bookCatogaryObject.Data.Rows[i].String[m].Id;
            DataClassArray[i].collectionDataClass[m].thumbnail = bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail;
            DataClassArray[i].collectionDataClass[m].collectionImage = 
                await GetImage(bookCatogaryObject.Data.Rows[i].String[m].CollectionThumbnail);
        }
    }
}

public static async Task<Texture2D> GetImage(string imageURL)
{
    using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(imageURL))
    {
        var asyncOperation = www.SendWebRequest();
        while (asyncOperation.isDone == false)
        {
            await Task.Delay(1000 / 30);
        }

        if (www.isNetworkError || www.isHttpError)
        {
            Debug.Log($"{www.error}, URL:{www.url}");
            return null;
        }
        else
        {
            return DownloadHandlerTexture.GetContent(www);
        }
    }
} 
Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
Omkar P
  • 29
  • 5