iOS Question How to obtain the bytes available in a Inputstream

shirlun

Active Member
Licensed User
Longtime User
Hi, Erel

In B4A I can use Inputstream.BytesAvailable to obtain the available bytes, how can I do in B4I ?

Thanks
 

shirlun

Active Member
Licensed User
Longtime User
In a B4A timer, I check InputStream.BytesAvailable to see any incoming data and receive it, this can read data from socket stream directly. Without checking InputStream.BytesAvailable, reading socket stream will block the execution.

AsyncStreams are complicate that I must copy the newdata() to a buffer, another question is how to handle multiple connection concurrently ?
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
The following code can be compiled, but error in execution, how can I correct it ?

The log:

*** -hasBytesAvailable only defined for abstract class. Define -[B4IFastSocket hasBytesAvailable]!


B4X:
Sub icGetBytesAvailable(i As InputStream) As Int

    Dim no As NativeObject = Me
   
    Return no.RunMethod("GetBytesAvailable:", Array(i))
   
End Sub

#If OBJC
- (int *)GetBytesAvailable:(NSInputStream *)inputstream {
  int b;
  b = [inputstream hasBytesAvailable];
  return b;
}
#End If
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
There are many mistakes in this code. Again I recommend you to learn how to work with AsyncStreams. Reading or writing data directly to a network stream will cause your app to freeze if the network is slow.

You can call hasBytesAvailable with:
B4X:
Dim no As NativeObject = Socket.InputStream
Dim b As Boolean = no.GetField("hasBytesAvailable").AsBoolean
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
The same error generated in both debug and release mode, thanks.

After this porting from B4A I will start working with AsyncStreams.
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
Thank you for your help.

B4X:
'Code module
#Region  Project Attributes 
    #ApplicationLabel: B4i Example
    #Version: 1.0.0 
    'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown
    #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight
    #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown
    #Target: iPhone, iPad
    #MinVersion: 7
#End Region

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.
    Public App As Application
    Public NavControl As NavigationController
    Private Page1 As Page

    Private s As Socket

End Sub

Private Sub Application_Start (Nav As NavigationController)
    NavControl = Nav
    Page1.Initialize("Page1")
    Page1.Title = "Page 1"
    Page1.RootPanel.Color = Colors.White
    NavControl.ShowPage(Page1)
End Sub

Private Sub Page1_Resize(Width As Int, Height As Int)

    s.Initialize("test")
    s.Connect("192.168.0.81", 2020, 10000)
   
End Sub

Sub test_connected(sucessful As Boolean)
   
    If icGetBytesAvailable Then
        Msgbox("have incoming data", "test")
    End If
     
End Sub

Sub icGetBytesAvailable As Boolean

    Dim no As NativeObject = s.InputStream
    Dim b As Boolean = no.GetField("hasBytesAvailable").AsBoolean
   
    Return b
   
End Sub

Private Sub Application_Background
   
End Sub

The log:

Application_Start
Application_Active
Error occurred on line: 49 (Main)
*** -hasBytesAvailable only defined for abstract class. Define -[B4IFastSocket hasBytesAvailable]!
Stack Trace: (
CoreFoundation <redacted> + 150
libobjc.A.dylib objc_exception_throw + 38
CoreFoundation <redacted> + 0
Foundation NSRequestConcreteImplementation + 174
Foundation <redacted> + 32
Foundation <redacted> + 64
Foundation <redacted> + 224
B4i Example -[B4INativeObject GetField:] + 124
B4i Example -[b4i_main _icgetbytesavailable] + 990
B4i Example -[b4i_main _test_connected:] + 708
CoreFoundation <redacted> + 68
CoreFoundation <redacted> + 292
B4i Example +[B4I runDynamicMethod:method:throwErrorIfMissing:args:] + 1786
B4i Example -[B4IShell runMethod:] + 574
B4i Example -[B4IShell raiseEventImpl:method:args::] + 2212
B4i Example -[B4IShellBI raiseEvent:event:params:] + 1442
B4i Example __50-[B4I raiseEventFromDifferentThread:event:params:]_block_invoke + 74
libdispatch.dylib <redacted> + 10
libdispatch.dylib <redacted> + 22
libdispatch.dylib _dispatch_main_queue_callback_4CF + 1532
CoreFoundation <redacted> + 8
CoreFoundation <redacted> + 1590
CoreFoundation CFRunLoopRunSpecific + 516
CoreFoundation CFRunLoopRunInMode + 108
GraphicsServices GSEventRunModal + 160
UIKit UIApplicationMain + 144
B4i Example main + 108
libdyld.dylib <redacted> + 2
)
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
With AsyncStreams, handling fragmented data is hard since I can't rewrite the codes of sender.
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
The protocol is, sender sends variable length packets continuously, the app takes action according to the data, update UI or receive file etc.

With AssynStreams, in event handling loop, NewData event will not raise again, lacking of data will cause problem, whether I can temporarily disable the AssynStreams and read data directly from Socket.InputStream ?
 
Upvote 0

shirlun

Active Member
Licensed User
Longtime User
Seems I found a solution, collect data in NewData event, and setup a timer to do handling routine, the problem caused by lacking data is disappeared.
 
Upvote 0
Top