iOS Question B4X same code different results

luke2012

Well-Known Member
Licensed User
Longtime User
Hi All,
I'm developing my first B4XPages (by @Erel) App for my client in order to obtain an Android and a iOS version of the app.

The B4A version app runs correctly without blocking errors, but if I run it in the B4i version it encounters a blocking error that crashes it.

The code that is executed is a shared code (method of a class) between the two projects and it is the following ...

B4X:
Sub GetNIDs (nid As Int, aUser As String, aPsw As String) As ResumableSub
 
    Wait For (GetJSONByNID (nid, aUser, aPsw)) Complete (WSResult As String)
    Private WSResponse As String = WSResult
 
    Log ("GetSubCatsNIDs | WSResponse " & WSResponse)
 
    If WSResponse = "" Then
        Private NoData As List:NoData.Initialize
        Return NoData
    End If
     
    'PARSE WS RESPONSE
    Try
        'Check if the response is a valid JSON
        Dim parser As JSONParser
        parser.Initialize(WSResponse)
        Dim JRoot As Map = parser.NextObject
     
        'CUSTOM CODE FOR PARSING
        Dim field_elenco_nodi_categorie As List = JRoot.Get(FIELD_SUBCATS_NIDS)
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Private nids As String = value.Replace(CRLF, STR_SEP)
 
        Log ("nids: " & nids)

        Private arrNIDs() As String '<--- Breakpoint


B4A - DEBUG RESULT
'Log ("nids: " & nids)
nids: {value=32
,33
,34
,35
,37
,38
,41
,104}

B4i - DEBUG RESULT
'Log ("nids: " & nids)
nids: (read only map) {, value = "32
\n33
\n34
\n35
\n37
\n38
\n41
\n104";,}

So the point is that in order to work properly the app expects the returned numbers above (32,33,34,35,37,38,41,104) to be separated by a ",".
This code works fine within B4A but within B4i the result isn't the expected:
32\n33\n34\n35\n37\n38\n41\n104";,

Has it happened to any of you too? Please how can I solve this unexpected problem?

thanks in advance 4 your suggestions
Luca.
 
Last edited:
Solution
Based on the logs in post #10, it looks like you are mistakenly converting a Map to a string.

Correct code:
B4X:
Dim value As Map = field_elenco_nodi_categorie.Get(0)

Pendrush

Well-Known Member
Licensed User
Longtime User
As I don't know value of value and STR_SEP:
B4X:
 Dim value As String = field_elenco_nodi_categorie.Get(0)
 value = value.Replace(CRLF, ",").Replace("\n", ",")
 
Upvote 0

hatzisn

Expert
Licensed User
Longtime User
Please also note that if you parse JSON in B4i it will create an immutable map. This means that it cannot be changed.
The solutions is to create a second map and copy all keys and values in the second map.

B4X:
Sub RecreateMapFromJSON(m As Map) As Map
    Dim m2 As Map
    m2.Initialize
  
    For Each k As String In m.Keys
        m2.Put(k, m.Get(k))
    Next
  
    Return m2
End Sub

Further more why do you create variables with the Private keyword? Since they are in the sub the scope is enclosed only in it.
 
Upvote 1

luke2012

Well-Known Member
Licensed User
Longtime User
As I don't know value of value and STR_SEP:
B4X:
 Dim value As String = field_elenco_nodi_categorie.Get(0)
 value = value.Replace(CRLF, ",").Replace("\n", ",")

B4X:
Public STR_SEP As String = ","

STR_SEP is the separator char.
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
Hi all,
the final purpose is to obtain a list (see lstNIDs within code) of numbers contained within the "field_list_nodi_categorie" field (see JSON file attached).
I ran the code below with B4A and B4i and attached the log results and the debugger screen.

So the point is that ".Replace(CRLF, STR_SEP)" works as expected within B4A but for some reason not within B4i (as you can see from the log / debugger - see attached files).

Am I doing something wrong or is it a bug of the .Replace () method inside B4i?

B4X:
    Try
        'Check if the response is a valid JSON
        Dim parser As JSONParser
        parser.Initialize(WSResponse)
        Dim JRoot As Map = parser.NextObject
  
        'the final purpose is to obtain a list of numbers contained within the json file attached in the          "field_list_nodi_categorie" field.
        'numbers within field "field_list_nodi_categorie" has CRLF attached on the left
        'STR_SEP = ","
  
        Dim field_elenco_nodi_categorie As List = JRoot.Get(FIELD_SUBCATS_NIDS)
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Dim nids As String = value.Replace(CRLF, STR_SEP)
  
        Log ("GetSubCatsNIDs | value: " & value)
        Log ("GetSubCatsNIDs | nids: " & nids)
  
        Private arrNIDs() As String
        arrNIDs = Regex.Split(STR_SEP, nids)
        Private lstNIDs As List
        lstNIDs.Initialize
        For i=0 To arrNIDs.Length-1
            Private strNID As String = arrNIDs(i)
            lstNIDs.Add(GetNumFromStr(strNID))
        Next
    Catch
        'string input is not valid
        Log ("API ERROR (GetSubCatsNIDs) - " & LastException.Message)
        Private lstNIDs As List
        lstNIDs.Initialize 'return an empty list
    End Try

    Return lstNIDs

@Erel, first of all, thanks for your reply.
Ok i will try to create a small project that include relevant code and the json file (you can see the json data also within the attached "json_file.txt").
 

Attachments

  • log_B4A.txt
    1.8 KB · Views: 114
  • lstNIDS_B4A.png
    lstNIDS_B4A.png
    56.7 KB · Views: 112
  • json_file.txt
    1.5 KB · Views: 100
  • log_B4i.txt
    2 KB · Views: 106
  • lstNIDS_B4i.png
    lstNIDS_B4i.png
    23.3 KB · Views: 113
Last edited:
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
Please create a small B4XPages project with the code and json file and upload it.

Hi Erel,
I created a small project* that exactly reproduces the relevant code and json data of the original project.

*B4XPages_test.zip (manually zipped by me)
*Project.zip (generated by "ide://run?File=%B4X%\Zipper.jar&Args=%PROJECT_NAME%.zip")

Note:
The correct (log) result should be: 18 19 22 24 93 106 108 123 126 128 132 149 155 171 (14 numbers)

As you can see (from the attached log files and also from the runtime logs), running the project in version B4A and version B4i the result is not the same (even if exactly the same code is executed).

How can I solve this problem?

Thanks.
 

Attachments

  • B4A_log_result_ok.txt
    158 bytes · Views: 106
  • B4i_log_result_ko.txt
    105 bytes · Views: 102
  • B4XPages_test.zip
    10.4 KB · Views: 99
  • Project.zip
    14.4 KB · Views: 98
Last edited:
Upvote 0

klaus

Expert
Licensed User
Longtime User
Have you tried to zip the project clicking on this line on top of the B4XMainPage ?
'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=%PROJECT_NAME%.zip
It may look a bit different in your project.
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
Have you tried to zip the project clicking on this line on top of the B4XMainPage ?
'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=%PROJECT_NAME%.zip
It may look a bit different in your project.
Yes thanks. See the #7 update.
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
The issue is that the JSON parser for B4i returns a completely different string for this line in your code
B4X:
Dim value As String = field_elenco_nodi_categorie.Get(0)
B4A returns
{value=18

19

22

24

93

106

108

123

126

128

132

149

155

171}
B4i returns
(read only map) {
value = "18
\n19
\n22
\n24
\n93
\n106
\n108
\n123
\n126
\n128
\n132
\n149
\n155
\n171";
}
A simple solution for the difference is to just let Regex.Matcher do its job. You're almost there with the code you have, but instead of
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Dim nids As String = value.Replace(CRLF, STR_SEP)
        
'        Log ("GetSubCatsNIDs | value: " & value)
'        Log ("GetSubCatsNIDs | nids: " & nids)
        
        Private arrNIDs() As String
        arrNIDs = Regex.Split(STR_SEP, nids)
        Private lstNIDs As List
        lstNIDs.Initialize
        For i=0 To arrNIDs.Length-1
            Private strNID As String = arrNIDs(i)
            lstNIDs.Add(GetNumFromStr(strNID))
        Next
With GetNumFromStr code being
B4X:
Sub GetNumFromStr(aStr As String) As Int
    Dim m As Matcher = Regex.Matcher("\d+", aStr)
    If m.Find Then
        Dim number As Int = m.Match
        'Log(number)
    End If
    Return number
End Sub
Just merge GetNumFromStr logic with the previous code and forget about String.Replace and Regex.Split and do
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Private lstNIDs As List
        lstNIDs.Initialize
        Dim m As Matcher = Regex.Matcher("\d+", value)
        Do While m.Find
            Dim number As Int = m.Match
            lstNIDs.Add(number)
            'Log(number)
        Loop
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
The issue is that the JSON parser for B4i returns a completely different string for this line in your code
B4X:
Dim value As String = field_elenco_nodi_categorie.Get(0)
B4A returns

B4i returns

A simple solution for the difference is to just let Regex.Matcher do its job. You're almost there with the code you have, but instead of
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Dim nids As String = value.Replace(CRLF, STR_SEP)
       
'        Log ("GetSubCatsNIDs | value: " & value)
'        Log ("GetSubCatsNIDs | nids: " & nids)
       
        Private arrNIDs() As String
        arrNIDs = Regex.Split(STR_SEP, nids)
        Private lstNIDs As List
        lstNIDs.Initialize
        For i=0 To arrNIDs.Length-1
            Private strNID As String = arrNIDs(i)
            lstNIDs.Add(GetNumFromStr(strNID))
        Next
With GetNumFromStr code being
B4X:
Sub GetNumFromStr(aStr As String) As Int
    Dim m As Matcher = Regex.Matcher("\d+", aStr)
    If m.Find Then
        Dim number As Int = m.Match
        'Log(number)
    End If
    Return number
End Sub
Just merge GetNumFromStr logic with the previous code and forget about String.Replace and Regex.Split and do
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Private lstNIDs As List
        lstNIDs.Initialize
        Dim m As Matcher = Regex.Matcher("\d+", value)
        Do While m.Find
            Dim number As Int = m.Match
            lstNIDs.Add(number)
            'Log(number)
        Loop

Hi @OliverA,
great workaroud suggestion! It works fine :)
The only issue is that the JSON parser doesn't work in the same way within B4A and B4i.
I expected it to work the same way.
 
Upvote 0

luke2012

Well-Known Member
Licensed User
Longtime User
The issue is that the JSON parser for B4i returns a completely different string for this line in your code
B4X:
Dim value As String = field_elenco_nodi_categorie.Get(0)
B4A returns

B4i returns

A simple solution for the difference is to just let Regex.Matcher do its job. You're almost there with the code you have, but instead of
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Dim nids As String = value.Replace(CRLF, STR_SEP)
       
'        Log ("GetSubCatsNIDs | value: " & value)
'        Log ("GetSubCatsNIDs | nids: " & nids)
       
        Private arrNIDs() As String
        arrNIDs = Regex.Split(STR_SEP, nids)
        Private lstNIDs As List
        lstNIDs.Initialize
        For i=0 To arrNIDs.Length-1
            Private strNID As String = arrNIDs(i)
            lstNIDs.Add(GetNumFromStr(strNID))
        Next
With GetNumFromStr code being
B4X:
Sub GetNumFromStr(aStr As String) As Int
    Dim m As Matcher = Regex.Matcher("\d+", aStr)
    If m.Find Then
        Dim number As Int = m.Match
        'Log(number)
    End If
    Return number
End Sub
Just merge GetNumFromStr logic with the previous code and forget about String.Replace and Regex.Split and do
B4X:
        Dim field_elenco_nodi_categorie As List = JRoot.Get("field_elenco_nodi_categorie")
        Dim value As String = field_elenco_nodi_categorie.Get(0)
        Private lstNIDs As List
        lstNIDs.Initialize
        Dim m As Matcher = Regex.Matcher("\d+", value)
        Do While m.Find
            Dim number As Int = m.Match
            lstNIDs.Add(number)
            'Log(number)
        Loop

"The issue is that the JSON parser for B4i returns a completely different string for this line in your code":
The problem is that my B4XPages App is heavily based (per my client's specifications) on JSON parsing, so on thousands of lines of code there are several calls to the JSON parser and if on the B4A version it works one way but in the B4i version it works in another way it could become a problem.
In relation to JSON parsing, the one already tested and working on the B4A / Android App may not work well on the B4i / iOS version and this wastes much more time in this case.

@Erel is this JSON library problem solvable in your opinion?
 
Upvote 0
Top