iOS Question B4i issues - B4Xtables, ButtonBar

Kevin Hartin

Active Member
Licensed User
Longtime User
I have a working app in B4a and I am in the process of porting it to B4i.

The app is quite straightforward, with plenty of interaction with an API using HttpJob and then populating a B4Xtable. No issue in B4a, but B4i is throwing up some inconsistencies and errors.

One page (PayLinks) happily gets it's dataset through the API call, displays it in the log and runs through the procedure to add it to the B4Xtable, but the table doesn't show. I also found that I had to initialise the B4Xtable in B4i, but not in B4a.

Another page (Transactions) crashes, despite using near identical code. It seems to be B4Xtable related but this is happening in the middle of the WaitFor HttpJob procedure, as I see the URL in the log and then the following error;
Error:
https://samoapayments.com/api/transactions/1000001
Error occurred on line: 120 (B4XTable)
Object was not initialized (UIView)
Stack Trace: (
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 809328
  libobjc.A.dylib      objc_exception_throw + 88
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 1371660
  SP Client            -[B4IObjectWrapper object] + 76
  SP Client            -[B4XViewWrapper asPanelWrapper] + 52
  SP Client            -[B4XViewWrapper LoadLayout::] + 56
  SP Client            -[ResumableSub_b4xtable_DesignerCreateView resume::] + 2964
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 284356
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 283984
  SP Client            +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 776
 SP Client            -[B4IShell runMethod:] + 320
 SP Client            -[B4IShell raiseEventImpl:method:args::] + 932
 SP Client            -[B4IShellBI raiseEvent:event:params:] + 1008
 SP Client            -[B4IDelegatableResumableSub resume::] + 300
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 6876
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 112636
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 232208
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 69320
 libdispatch.dylib    _dispatch_main_queue_callback_4CF + 44
 CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 434868
 CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 121660
 CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 117356
 GraphicsServices     GSEventRunModal + 120
 UIKitCore            C768F963-A0CC-3F5C-A1D3-2E06D53A2381 + 646648
 UIKitCore            UIApplicationMain + 336
 SP Client            main + 100
 dyld                 8ACDB580-8AB7-38C0-A586-E667ADB1C11C + 20008
)

Another inconsistency issue is when trying to add a couple of TopRightButtons. I managed to get them to show, but couldn't get them to trigger anything, so I tried a few alternate methods, but they wouldn't even show. I went back to the code that showed the buttons, two in a little white sausage, but they now dont show and instead I have a big white empty sausage that crashes when touched.

And finally, I've disabled the Firebase Notifications by commenting out the analytics.Initialize as it complains it can't find the GoogleService-Info.plist Where should this reside?

Any help will be much appreciated.

Kev
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Initialize as it complains it can't find the GoogleService-Info.plist Where should this reside?
Inside <project>\Files\Special

About the B4XTable - when you load a layout with B4XTable, the table isn't immediately ready. Internally there is a call to Sleep(0) and then the table loads its own layout.
It looks like something is broken at this step. Maybe you already modified the table in some way.
You can add Sleep(0) in your code to let the table asynchronously load itself.

About BarButtons - check this example: https://www.b4x.com/android/forum/t...k-for-managing-multiple-pages.118901/#content
 
Upvote 0

Kevin Hartin

Active Member
Licensed User
Longtime User
Inside <project>\Files\Special

About the B4XTable - when you load a layout with B4XTable, the table isn't immediately ready. Internally there is a call to Sleep(0) and then the table loads its own layout.
It looks like something is broken at this step. Maybe you already modified the table in some way.
You can add Sleep(0) in your code to let the table asynchronously load itself.

About BarButtons - check this example: https://www.b4x.com/android/forum/t...k-for-managing-multiple-pages.118901/#content
At what stage would I put a Sleep(0)?
 
Upvote 0

Kevin Hartin

Active Member
Licensed User
Longtime User
There isn't enough information here to actually point to the problem. Post the code that loads and interacts with the table.
Sorry, I think my first attempt to attach was too big

Kev
 

Attachments

  • Backup SPclient 2026-04-10 12.15.zip
    508.9 KB · Views: 15
Upvote 0

Kevin Hartin

Active Member
Licensed User
Longtime User
Sorry but this project is too large for me to go over it.

If you are unable to solve the issue with B4XTable, then try to post the relevant code snippets.
Erel,

Following is the code that works perfectly under B4a to load the paylinkTable which returns the following screen on my iPad compared to the Android;
paylinkTable.jpg
paylinkAndroid.jpg

paylinkTable:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    
    Drawer.Initialize(Me, "Drawer", Root, 200dip)
    Drawer.CenterPanel.LoadLayout("paylink")
    Drawer.LeftPanel.LoadLayout("menu")
    HamburgerIcon = xui.LoadBitmapResize(File.DirAssets, "hamburger.png", 32dip, 32dip, True)

    Dim bb As BarButton
    bb.InitializeBitmap(HamburgerIcon, "hamburger")
    B4XPages.GetNativeParent(Me).TopLeftButtons = Array(bb)
    B4XPages.GetNativeParent(Me).TopRightButtons = Array(misc.CreateFABarImg("refresh.png", "REFRESH"),misc.CreateFABarImg("new.png", "NEW"))

    paylinkTable.Initialize(paylinkTable,"paylinkTable")
    paylinkTable.HeaderFont = xui.CreateDefaultBoldFont(12)
    paylinkTable.HeadersHeight = 25dip
    paylinkTable.AddColumn("Business", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("Created", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("Name", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("Description", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("Amount", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("Status", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("ID", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("GUID", paylinkTable.COLUMN_TYPE_TEXT)
    paylinkTable.AddColumn("URL", paylinkTable.COLUMN_TYPE_TEXT)
    Log("Cols: "&paylinkTable.Columns.Size)
    paylinkTable.VisibleColumns.RemoveAt(8)
    paylinkTable.VisibleColumns.RemoveAt(7)
    paylinkTable.VisibleColumns.RemoveAt(6)

    showPaylinks
End Sub

Sub showPaylinks()
    Dim getPaylink As HttpJob 'ignore
    getPaylink.Initialize("getPaylink", Me)
    Log("https://samoapayments.com/api/paylink/"&Main.clientID)
    getPaylink.PostString("https://samoapayments.com/api/paylink/"&Main.clientID,"test")
    getPaylink.GetRequest.SetHeader("Authorization","Bearer "&Main.token )
    Wait For (getPaylink) JobDone (Job As HttpJob)
    If Job.Success Then
        Log("getPaylink Job.GetString:"&Job.GetString)
        If Job.GetString <> "NO RECORDS" Then
            Dim parser As JSONParser
            parser.Initialize(Job.GetString)
            Dim rawData As List = parser.NextArray
            Dim formattedList As List
            formattedList.Initialize

            For Each colroot As Map In rawData
                Dim sBusiness As String = colroot.Get("Business")
                Dim sCreated As String = colroot.Get("Created")
                Dim sName As String = colroot.Get("Name")
                Dim sDesc As String = colroot.Get("Description")
                Dim sAmount As String = colroot.Get("Amount")
                Dim sStatus As String = colroot.Get("Status")
                Dim sID As String = colroot.Get("ID")
                Dim sGUID As String = colroot.Get("GUID")
                Dim sURL As String = colroot.Get("URL")
                formattedList.Add(Array As String(sBusiness, sCreated, sName, sDesc, sAmount, sStatus, sID, sGUID, sURL))
            Next
            Log(formattedList.Size)
            paylinkTable.SetData(formattedList)
        End If
    End If
    Job.Release
End Sub

For the transactions, the code is virtually identical apart from the column count and url to get the dataset, however it looks to be crashing as a result of the
Wait For (getTransactions) JobDone (Job As HttpJob) not completing as the Log("OK3") never runs and it instead skips to OK7.

The URL works fine https://samoapayments.com/api/transactions/1000097?test or https://samoapayments.com/api/transactions/1000001?test for some real Data

Logs:
Class (b4i_b4xformatter) instance released.
OK1
https://samoapayments.com/api/transactions/1000097
OK2
OK7
Error occurred on line: 120 (B4XTable)
Object was not initialized (UIView)
Stack Trace: (
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 809328
  libobjc.A.dylib      objc_exception_throw + 88
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 1371660
  SP Client            -[B4IObjectWrapper object] + 76
  SP Client            -[B4XViewWrapper asPanelWrapper] + 52
  SP Client            -[B4XViewWrapper LoadLayout::] + 56
  SP Client            -[ResumableSub_b4xtable_DesignerCreateView resume::] + 2964
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 284356
  CoreFoundation       2F32D384-4637-3018-843E-4FC875B865C4 + 283984
  SP Client            +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 776
 SP Client            -[B4IShell runMethod:] + 320
 SP Client            -[B4IShell raiseEventImpl:method:args::] + 932
 SP Client            -[B4IShellBI raiseEvent:event:params:] + 1008
 SP Client            -[B4IDelegatableResumableSub resume::] + 300
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 6876
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 112636
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 232208
 libdispatch.dylib    904D48A3-D99E-3962-BFA9-C3DFB66BBA83 + 69320
 libdispatch.dylib    _dispatch_main_queue_callback_4CF + 44

transTable:
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1

    Drawer.Initialize(Me, "Drawer", Root, 200dip)
    Drawer.CenterPanel.LoadLayout("transactions")
    Drawer.LeftPanel.LoadLayout("menu")
    HamburgerIcon = xui.LoadBitmapResize(File.DirAssets, "hamburger.png", 32dip, 32dip, True)

    Dim bb As BarButton
    bb.InitializeBitmap(HamburgerIcon, "hamburger")
    B4XPages.GetNativeParent(Me).TopLeftButtons = Array(bb)
    B4XPages.GetNativeParent(Me).TopRightButtons = Array(misc.CreateFABarImg("refresh.png", "REFRESH"))

    transTable.Initialize(transTable,"transTable")
    transTable.HeaderFont = xui.CreateDefaultBoldFont(12)
    transTable.HeadersHeight = 25dip
    Dim DateCol As B4XTableColumn = transTable.AddColumn("Date", transTable.COLUMN_TYPE_TEXT)
    DateCol.Width = 100dip
    transTable.AddColumn("Name", transTable.COLUMN_TYPE_TEXT)
    transTable.AddColumn("Type", transTable.COLUMN_TYPE_TEXT)
    transTable.AddColumn("Amount", transTable.COLUMN_TYPE_TEXT)
    transTable.AddColumn("Status", transTable.COLUMN_TYPE_TEXT)
    transTable.AddColumn("ID", transTable.COLUMN_TYPE_TEXT)
    
    Log("OK1")
    showTransactions
    Log("OK7")
End Sub

Sub showTransactions()
    Dim getTransactions As HttpJob 'ignore
    getTransactions.Initialize("getTransactions", Me)
    Log("https://samoapayments.com/api/transactions/"&Main.clientID)
    getTransactions.PostString("https://samoapayments.com/api/transactions/"&Main.clientID,"test") ' test bypasses some server security
    getTransactions.GetRequest.SetHeader("Authorization","Bearer "&Main.token )
    Log("OK2")
    Wait For (getTransactions) JobDone (Job As HttpJob)
    Log("OK3")
    If Job.Success Then
        Log("getTransactions Job.GetString: "&Job.GetString)
        If Job.GetString <> "NO RECORDS" Then
            Dim parser As JSONParser
            parser.Initialize(Job.GetString)
            Dim rawData As List = parser.NextArray
            Dim formattedList As List
            formattedList.Initialize

            For Each colroot As Map In rawData
                Dim sDate As String = colroot.Get("Date")
                Dim sName As String = colroot.Get("Name")
                Dim sType As String = colroot.Get("Type")
                Dim sAmount As String = colroot.Get("Amount")
                Dim sStatus As String = colroot.Get("Status")
                Dim sID As String = colroot.Get("ID")
                formattedList.Add(Array As String(sDate, sName, sType, sAmount, sStatus, sID))
            Next
            Log(formattedList.Size)
            transTable.SetData(formattedList)
        End If
    End If
    Log("OK4")
    Job.Release
End Sub

Thanks,
Kev
 
Upvote 0
Top