iOS Question Problem with List.add

Shay

Well-Known Member
Licensed User
see this, very odd:

I am adding in loop:
MyPoint.Initialize(Lat1,Lng1)
WayPoints.Add(MyPoint)

this is from the log, each time I add another entry to list, all previous are changing as the last one

<B4IList: (
"Lat: 32.065900, Lon: 34.829300"
)>
<B4IList: (
"Lat: 32.065870, Lon: 34.829910",
"Lat: 32.065870, Lon: 34.829910"
)>
<B4IList: (
"Lat: 32.066230, Lon: 34.829930",
"Lat: 32.066230, Lon: 34.829930",
"Lat: 32.066230, Lon: 34.829930"
)>
<B4IList: (
"Lat: 32.066340, Lon: 34.829950",
"Lat: 32.066340, Lon: 34.829950",
"Lat: 32.066340, Lon: 34.829950",
"Lat: 32.066340, Lon: 34.829950"
)>
 

Shay

Well-Known Member
Licensed User
I have in the function code: (above this line)
Private MyPoint As LatLng

the log above is from:
log(WayPoints)
The problem is the entire list is changing all the time
 

Brian Robinson

Active Member
Licensed User
Hi Shay,

You need to Dim MyPoint inside the loop.

You have only created 1 variable. Each time you add it to the list, it is creating a reference pointer to the original variable, which you change to the last way point.

Example:
Private MyPoint as LatLng create a position in memory of (X1)

This is what happens in the loop
Loop 1
MyPoint = (Lat 111, Long 222) - this value is stored in (X1)
List.Add(MyPoint) - This actually just adds a pointer to (X1)
Loop 2
MyPoint = (Lat 112, Long 221) - This value is stored in (X1)
List.Add(MyPoint) - Adds another pointer to (X1)
*** At this point, both list items are pointing to the same position in memory (X1) which has the value of (Lat 112, Long 221)
End Loop

Your code needs to look like this:

B4X:
For iLoop = 0 to 10
  Dim MyPoint as LatLng
  MyPoint.Initialize(Lat1,Lng1)
  WayPoints.Add(MyPoint)
Next
Each time the loop is executed, MyPoint is reserved in memory (Dim) in a new location (X1,X2,X3....)

Hope this helps.

Cheers
Brian
 

Shay

Well-Known Member
Licensed User
I think my code is ok (not all the module)
here it is:

on class global:
Private WayPoints As List

here I have some loop of:
decodePoly(OverViewPolyLine,listMpi)

B4X:
Sub decodePoly(encoded As String, poly As List)
    Private b, index, Lat, Lng, dlat, dlng, flat, flng, shift, result As Int : index = 0 : Lat = 0 : Lng = 0
    Private MyPoint As LatLng
    Private Lat1, Lng1 As Double
   
    Do While index < encoded.Length      
        shift = 0 : result = 0       
        Do While True
            b = Asc(encoded.SubString2(index, index + 1)) - 63 : index = index + 1
            result = Bit.OR(result, Bit.ShiftLeft( Bit.AND( b, 0x1f), shift))
            shift = shift + 5
            If b < 0x20 Then Exit
        Loop
      
        If Bit.AND(result, 1) = 1 Then
            dlat = Bit.Not(Bit.ShiftRight(result, 1))
        Else
            dlat = Bit.ShiftRight(result, 1)
        End If
        Lat = Lat + dlat
       
        shift = 0 : result = 0
        Do While True
            b = Asc(encoded.SubString2(index, index + 1)) - 63 : index = index + 1
            result = Bit.OR(result, Bit.ShiftLeft(Bit.AND(b, 0x1f), shift))
            shift = shift + 5
            If b < 0x20 Then Exit
        Loop
       
        If Bit.AND(result, 1) = 1 Then
            dlng = Bit.Not(Bit.ShiftRight(result, 1))
        Else
            dlng = Bit.ShiftRight(result, 1)
        End If
        Lng = Lng + dlng
        flat = Lat
        flng = Lng
      
        Dim mpiCurrent As MapPointItem
        mpiCurrent.Initialize
        mpiCurrent.iPassed = 0
        Lat1 = flat / 1E5
        Lng1 = flng / 1E5
        MyPoint.Initialize(Lat1,Lng1)
        WayPoints.Add(MyPoint)
Log(WayPoints)

    Loop
  
End Sub
anyway the list should not be changed completely since it is declared on global
 

Brian Robinson

Active Member
Licensed User
Actually it was Erel who pointed it out.

I just tried to offer a bit of explanation around why to put it there. Hope I didn't confuse things.
 

Shay

Well-Known Member
Licensed User
Thanks I moved the line
on Sub decodePoly, line #2 to be above
WayPoints.Add(MyPoint)
and issue solved (I still can't understand why, since the list is declared on global, and entire list data cannot be changed - AFAIK)
 

klaus

Expert
Licensed User
I still can't understand why, since the list is declared on global...
Brian Robinson explained it. If you dim MyPoint only once all MyPoints in the List point to the same instance of MyPoint.
To have different values for each row you need to dim a new instance of MyPoint for each row.
 

Brian Robinson

Active Member
Licensed User
Sorry, I tried my best with the explanation - English is my first language - but not my strong point. :(

I think the best thing to do would be to grab a book on programming and learn about memory storage and value vs reference as well as the scope of variables. There are so many texts that explain this concept, and once you understand it, it seems very simple, and gives you a better understanding on why. The idea is generally the same from language to language because at the end of it all that is how it works in machine code.

B4A, and most modern languages pretty much hide and make it much easier to work with these concepts, but they are concepts you need to know to understand what is going on. Sure you can just go "well I just need to remember that if I do the same sort of thing again I have to Instantiate (Dim) the variable just before I use it", but unless you actually understand why you could run into the same frustrations. I was lucky enough to learn to program in "C" and Assembler which gives a great understanding of memory usage and efficiency (but would never go back there).

I was going to give an explanation here, but it would be re-inventing the wheel and it would be in English, and you may find it easier to understand in your own language.

Long story short: do a search for "Value Types vs Reference Types" and also "Variable Scope"

Also, any help you need with this, let me know.

Cheers
Brian
 
Top