Saturday, October 31, 2015
Android Bluetooth APIs - Learning Part II
Below is the snippet to retrieve list of bonded devices.
Set pairedDevices = btAdapter.getBondedDevices();
getName() returns the public identifier of the devices
getAddress() returns the MAC address of the device
In order to find the nearby devices, which is called scanning we need to use the below code
btAdapter.startDiscovery() is the method to start scanning operation. btAdapter.cancelDiscovery() will cancel the initiated scanning
These two methods are working via Asynchronous feedbacks by Broadcast Receivers.
private final BroadcastReceiver receiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action))
{
BluetoothDevice device = intent.getParcellableExtra(BluetoothDevice.EXTRA_DEVICE);
}
}
}
Connecting to a Device:
Similar to any other connection, there is a Server and Client which communicates via RFCOMM sockets.
On Android, RFCOMM sockets are represented as BluetoothSocket object.
Below is the code to connect to a Bluetooth Device
public class ConnectThreads extends Thread
{
private BluetoothSocket bTSocket;
public boolean connect(BluetoothDevice btDevice, UUID uuid)
{
BluetoothSocket socket = null;
try
{
socket = btDevice.createRFCommSocketToServiceRecord()
}
catch(Exception ex)
{
ex.printStackTrace();
}
try
{
socket.connect();
}
catch(Exception ex)
{
ex.printStackTrace();
try
{
}
catch(Excpetion ex)
{
}
}
}
}
References:
Linphone Management of Bandwidth parameter
References:
https://www.linphone.org/docs/liblinphone/group__media__parameters.html#ga1e0c01a25f78d14c6813213adf795e54
https://www.linphone.org/docs/liblinphone/group__media__parameters.html#ga1e0c01a25f78d14c6813213adf795e54
SIP SDP bandwidth information
The SDP includes an optional bandwidth attribute with the following syntax
b=:
where is single alpha numeric word giving the meaning of the bandwidth figure, and where the default units of
bandwidth value is kilobits per second. This attribute specifies the proposed bandwidth to be used by the session or media.
The typical use is with the modifier “AS” (Application specific Maximum) which may be used to specify the total bandwidth for a
single media stream from one site (source)
another modifier value is CT. If the bandwidth of a session or a media in a session is different from the bandwidth implicit from the scope,
a b=“CT” line should be supplied for the session giving the proposed upper limit to the bandwidth used (the “conference total” bandwidth)
The primary purpose of this is to give an approximate idea as to whether two or more sessions can co-exist simultaneously. when using CT
modifier with RTP, if several RTP sessions are part of the conference, the conference total refers to the total bandwidth of all the RTP sessions.
References:
Quirks of Unzipping on MAC
Some of the files were not able to be unzipped using either “unzip” command or “ditto” command via terminal
however, since they were getting opened perfectly using the “Archive Utility”, one option was to use the
terminal to open such files. e.g. below
open -a "Archive Utility" 0B9822F3-FE6C-4FB6-AB47-C98DA932279D_205155390.zip
The only inconvenience is that we cannot specify the destination folder.
This can be automated using a simple shell script like this
for file in *; do
echo $file
open -a "Archive Utility" $file
done
References:
What is needed for Support IPv6
An operating system that support IPv6: Windows Vista and modern versions and Mac OS and Linux latest versions support IPv6. Windows XP doesnt, and we should not be using XP anymore.
A router with IPV6 support: Most of the modern routers comes with IPv6 support
An ISP that supports IPV6.
The below page helps to test the IPv6 http://ds.testmyipv6.com/
The IPv6 only test:
If we attempt to connect to this server and times out, then it means that we don’t have IPv6 path to the server. The below could be possible reason for this
1. The client is not having globally routable address on the internet and therefor not actually making the connection to this server
2. The client is IPv6 capable, but does not know that it is limited to the local network. But there is no IPv6 connectivity beyond the router
If the browser returns an error saying that the host cannot be found, then the DNS servers that we are using don’t know how to look up the address of the server based on the hostname. They are unable to resolve the AAAA record. If one is using the DNS server addresses provided by the ISP, then we need to ring them up and ask to fix ASAP.
If we are using local gateway or router for DNS, then router is not capable or forwarders used by the router (likely the ISP’s servers) is not capable.
IF browser is able to connect to IPV6 only page, but still shows red box when taking the Dual Stack test, the browser seems to be preferring IPV4 over IPV6, which is undesirable.
References
Serializing the objects Java
Serialization is quite simple, if we have requirement to Serialize and ArrayList that contains a number of Objects, below are the steps to do
1. Create the object that goes into the array list as Serializable objects
2. Optionally, add a field into the object which can tell the version of the class structure.
Now just add to the array list and serialize the array list, be
References:
http://www.journaldev.com/2452/java-serialization-example-tutorial-serializable-serialversionuid
1. Create the object that goes into the array list as Serializable objects
2. Optionally, add a field into the object which can tell the version of the class structure.
Now just add to the array list and serialize the array list, be
public class Accessory implements Serializable
{
private int type;
private int state;
private String name;
private String uuid;
public Accessory(int type, int state, String name, String uuid)
{
this.type = type;
this.state = state;
this.name = name;
this.uuid = uuid;
}
}
public void saveAccessories(ArrayList accessoryList)
{
try
{
FileOutputStream fos= new FileOutputStream("myfile");
ObjectOutputStream oos= new ObjectOutputStream(fos);
oos.writeObject(accessoryList);
oos.close();
fos.close();
}
catch(IOException ioe)
{
ioe.printStackTrace();
}
}
public ArrayList loadAccessories()
{
try
{
FileInputStream fis = new FileInputStream("myfile");
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
ois.close();
return (ArrayList)obj;
}
catch (Exception ex)
{
ex.printStackTrace();
}
return null;
}
References:
http://www.journaldev.com/2452/java-serialization-example-tutorial-serializable-serialversionuid
Friday, October 30, 2015
iOS Push Notification - Debugging
Since the app is not receiving the valid push notification token from OS, there are a few reasons why the APNS token does not get delivered to the app. One of them is network is blocking the 5223 for inbound and outbound TCP/TLS traffic.
If still not receiving the notification, we can figure out few things by installing a debug profile at the link below, which will let us give the device level Apple Notification server connection logs
Once installed, please restart the device while connected to Xcode, Once the device powers up and app is launched, we can see the logs in the Xcode console.
In the log, there will be logs from the process “apsd” which will help us analyze what is happening.
If would prefer to delete the is profile at later point, can do this by navigating to Settings > General > Profiles Delete APS logging profile.
References:
Android - Creating a Dynamic Grid view
For a sample application, i was trying to include a Dynamic grid view. The git hub project that is in the reference section looked to be
really useful. noting down few points on this.
Below are the main things that attracted to look into it.
- On long tap, the grid enters to edit mode
- when in edit mode, the icons jerk to give an iPhone like animation
- On tap of the icon, it just does the action as expected.
- When dragging an icon in edit mode, it adjusts each other nicely
- when dragged by holding, the view scrolls as well.
Below are the main classes in the project.
- DynamicGridView => Main View for the Grid view
- DynamicGridUtils => Utils methods for doing the model level tasks such as reordering, swapping etc.
- DynamicGridAdapterInterface => interface to be used with grid view
- AbstractDynamicGridAdapter ->
- BaseDynamicGridAdapter ->
Below are the steps to integrate this into a new project.
1. On the new project right click the project and select new Module
2. On the new module window, select import existing project
3. Specify the source directory and add the dynamic grid project from the git hub download
4. Open module settings, and add the dynamic grid as dependancy to the new app.
References:
Tuesday, October 20, 2015
Android TimerTask on Background Service
For creating a timer task and running it periodically, say for e.g. making a network ping periodically can be achieved by the below code
class TimeDisplayTimerTask extends TimerTask {
@Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
@Override
public void run() {
AppUtils.infoLog("--- Triggering Location Check ---");
displayTimeInfo();
}
});
}
}
if(mTimer != null) {
mTimer.cancel();
} // recreate new
mTimer = new Timer();
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
Handler is mainly used to post data from background thread to UI thread.
References:
Saturday, October 17, 2015
Android Dialog With Radio Buttons
The code is simple
final CharSequence[] photo = {"Manage Devices","Manage Connections"};
AlertDialog.Builder alert = new AlertDialog.Builder(MainActivity.this);
alert.setTitle("Settings For");
alert.setSingleChoiceItems(photo, -1, new
DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Log.v(LOG_TAG,"chosen "+which);
}
});
alert.show();
References:
Android Custom Adapter for Grid View
The aim was to display a grid icon and the label corresponding to it, just like below screenshot
This can be done by giving a layout for each cell and this layout view is returned as a layout defined in this file
A sample layout for this is
"1.0" encoding="utf-8"?
android:id="@+id/relativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:padding="5dp"
android:layout_height="64dp"
android:id="@+id/imageView1"
android:layout_width="64dp"
android:src="@drawable/ic_launcher"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:text="TextView"
android:layout_height="wrap_content"
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_below="@+id/imageView1"
android:layout_marginTop="2dp"
android:layout_centerHorizontal="true"
android:textSize="18sp"
android:ellipsize="marquee"
In the getView Method of the Adapter class, below will be the code
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder view;
LayoutInflater inflator = activity.getLayoutInflater();
if(convertView==null)
{
view = new ViewHolder();
convertView = inflator.inflate(R.layout.gridview_row, null);
view.txtViewTitle = (TextView) convertView.findViewById(R.id.textView1);
view.imgViewFlag = (ImageView) convertView.findViewById(R.id.imageView1);
convertView.setTag(view);
}
else
{
view = (ViewHolder) convertView.getTag();
}
view.txtViewTitle.setText(listCountry.get(position));
if(itemStates[position] == 0) {
view.imgViewFlag.setImageResource(listFlagOff.get(position));
}
else
{
view.imgViewFlag.setImageResource(listFlag.get(position));
}
return convertView;
}
}
It is convenient to have tag as object for each view. This way we can associate arbitrary object. Where as in iOS, the tag has to be always int.
References:
Thursday, October 15, 2015
Hands On With GitHub Repository - Part II
The main purpose of forking a repository is to propose changes and in other words, work together. Below are the steps to do that
1. Setup the Git
2. Clone the repository to the local repository
To clone, we can get the clone url and enter the following in the terminal
git clone
after cloning, we can see the details of the remote repository like this
git remote -v
git remote -v
origin https://github.com/mrrathish/TestGitProj.git (fetch)
origin https://github.com/mrrathish/TestGitProj.git (push)
in the above, essentially, it like the format below
origin https:github.com//
Now we need to add upstream repositories so that we can sync up.
git remote add upstream https://github.com/mrrathish/TestGitProj.git
After adding the upstream info, the remote -v command will give the details like below
git remote -v
origin https://github.com/mrrathish/TestGitProj.git (fetch)
origin https://github.com/mrrathish/TestGitProj.git (push)
upstream https://github.com/mrrathish/TestGitProj.git (fetch)
upstream https://github.com/mrrathish/TestGitProj.git (push)
In the above, the original format of upstream is,
upstream https://github.com//
Now everything is setup for Synching. Below gives info on how to sync the fork
to sync the online repository with the local one, below are the steps
1. git fetch upstream (this fetches the commits from master into the local branch upstream/master)
2. git checkout master (checkout fork’s local branch)
3. git merge upstream/master (merges the changes from upstream/master into the local master. This brings fork’s master in sync with the upstream master)
Note that Synching the fork only updates the local copy of the repository. To update the fork on github, one must Push the changes
References:
Tuesday, October 13, 2015
Hands on With GitHub repository - Part I
1. Set up A repo
first of all few configurations we need to do for the git repository.
1. name => git config —global user.name = “testgitun”
2. email address => git config —global user.email = “testgitun.gmail.com”
Authentication with GitHub from Git
When connecting to GitHub repository from Git, we need to authenticate with Github using either HTTPS or SSH
If connecting via HTTPS the password can be cached using a Credential Helper.
If clone with SSH, we must generate SSH keys on each computer we use to pull or push from GitHub.
2. Create A Repo
To put project in GitHub, first we need to create a repository for it to live in.
The Create New repository option is very easily locatable and To create a new repository, just need to provide the name and description of the project.
Free accounts can only create public repos while the paid accounts can create private repositories.
When creating a git repo, we have an option to add a README file. The examples in github is explaining few concepts around this. The github page itself gives option to
edit the content and preview. Once after preview, we can commit. the commit can be into the same master branch or we can create a new branch for this commit and generate a pull request.
When the pull request is generated, it appears on the github page and one can merge the changes and delete the branch that came in the pull request.
3. Forking A Repo
Fork is a copy of a repository. Forking allows us to do free experiments without affecting the original project.
Below is the usual practice:
- Fork Some one else’s project
- Make bug fix
- Submit a pull request
References:
Monday, October 12, 2015
Android Bluetooth Scanner - Starter Basics
Below are the tasks intended in this sample
- Enable bluetooth on a device
- Display a list of paired devices
- Discover and list nearest Bluetooth devices
- Connect and send data to another bluetooth device
There are two kinds of permissions
1. BLUETOOTH => used to connect, disconnect and transfer data with another bluetooth device
2. BLUTOOTH_ADMIN => allows to discover new bluetooth device and change device’s bluetooth settings
Application will need to use Bluetooth adapter for interfacing with the Bluetooth.
BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
if the Adapter is returned to be null, then the device does not have the Bluetooth feature
Application can get to know if the Bluetooth is enabled or not by using the API isEnabled. If not
enabled, it can enable it by using an intent provided by Android
if(!btAdapter.isEnabled())
{
Intent enableBT = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBT,REQUEST_BLUETOOTH);
}
A bluetooth device can be in any of the below states from perspective of Mobile Device
- Unknown
- paired
- connected
Paired devices know each other’s existence and share a link key, which can be used to authenticate, resulting in a
connection. Devices are automatically paired once encrypted connection is established.
Connected devices share RFCOMM channel, allowing them to send and receive data. A device may have many paired devices
but it can have only one connected devices at a time.
References:
iOS Work arounds with the ATS in Xcode 7 & iOS 9.0
In iOS 9.0, ATS enforces best practices during network calls, including the use of HTTPS.
If we want to avoid the ATS enforcement, by manually adding a plist entry, it is possible
This above is mainly useful if App is trying to connect to some arbitrary sites for e.g. WebBrowser
If app is trying to connect to certain known domains that doesnt for time being support TSL 1.2,
below can be used.
NSExceptionDomains
<!— include to allow subdomains
<!— include to allow HTTP requests
<!— Include to specify minimum TLS version
References:
Sunday, October 11, 2015
Swift Learning - Protocols Learning
The concept of Protocols is same as that of Objective C. It provides a blue print for methods, properties.
e.g is like below
protocol TestProtocol
{
var simpleDesc: String {get}
func adjust()
}
the {get} followed by simpleDesc indicates that it is read only.
Protocols are like first class types, which means that they can be treated like other named types.
class SimpleProtocol2: ExampleProtocol
{
var SimpleDescription: String = “Another very simple class”
fun adjust()
{
simpleDescroption += “adjusted”
}
}
var protocolArray : [ExampleProtoocl] = [SimpleClass(), SimpleClasse(), Simpleclass()]
References:
Android Fragments - Basic learning
Fragment is ui component that can live in an activity. A fragment is not a view by itself. instead, it has view inside. Because it is not a view, the process of adding fragment to activity is different. A fragment is added to ViewGroup inside an activity. The Fragments view is displayed this ViewGroup.
Below are the steps to create Fragments
- Create a Fragment Class
- Create a Fragment Layout XML
The subclassed Fragment class needs to override the onCreateView method inherited from the Fragment class.
The onCreateView gets the LayoutInflator, ViewGroup and Bundle as parameters
import android.app.Fragment;
public class TestFragment extends Fragment
{
@override
public View onCreateView(LayoutInflator inflator, ViewGroup group, Bundle savedInstanceS)
{
View rootView = inflator.inflate(R.layout.test_fragment,group,false);
return rootView;
}
}
Below is the code to add Fragment to the activity
public class TestActivity extends Activity
{
@override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
if(savedInstance == null)
{
getFragmentManager()
.beginTransaction()
.add(R.id.fragmentParentViewGroup,new TestFragment())
.commit();
}
}
}
The fragment is created inside the if statement. Unlike other View components, Activity remembers that what fragments were added to the Activity. Therefore we should add the fragment only once to the Activity.
References:
Friday, October 9, 2015
Enumeration and Structures in Swift
Enumerations and structures also has similar capabilities as of Classes in Swift.
enum Rank: Int
{
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String
{
switch self
{
case .Ace:
return “Ace”
case .Jack:
return “Jack”
case .Queen
return “Queen”
case .King
return “King”
default:
return String(self.rawValue)
}
}
}
let ace = Rank.Ace
let rawAceRawValue = ace.rawValue
we can use the init?(rawValue:) initializer to make an instance of an enumeration from a raw value.
if(let convertedRank = Rank(rawValue:3))
{
let desc = convertedRank.simpleDescription()
}
The raw values are not really required because the members of an enumeration are actual values.
struct is used to define a structure.
struct Card
{
var rank:Rank
var suite : Suit
func simpleDescription() -> String
{
return “suite has \(rank.simpleDescription())”
}
}
let structinit = Card (rank:.Three, suite:.Spades)
References:
Thursday, October 8, 2015
Swift Learning - classes and initializers
class Shape
{
var numberOfSide = 0
init(name:String)
{
self.name = name
}
func simpleDescription() -> String
{
return “A shape with number of sides \(numberOfSide)”
}
}
to create an instance of the class, just put a parentheses
var shapeObj = Shape()
shapeObj.numberOfSides = 10
var shapeDescription = shapeObj.simpleDescription()
init is called to specify the initializer.
var shapeObj = Shape(name:”SmpleShape”)
Like other programming languages, here also we have inheritence concept A class can only inherit from one class.
Application can use the the override keyword to override a method. If did not use, the compiler will give error.
There is a concept called fail able initilizer, which is represented by init? fail-able initializer can return nil after initialization.
e.g.
class Circle:NamedShape
{
var radius : Double
init?(radius:Double, name:String)
{
self.radius = radius
super.init(name:name)
if (radius < 0 )
{
return nil
}
}
}
A designated initializer indicates that its one of the primary initializers of a class. any initializer within a class must ultimately call through to a designated initializer. A convenience initializer is a secondary initializer which adds additional behavior for customization, but ultimately should go through the designated initializer. designated and convenience keywords are used for indicating this respectively.
A required keyword next to an initializer indicates that every subclass of the class that has initializer must implement its own version of the initializer.
type casting is a way to check the type of instance and to treat that instance as if it is a different superclass or subclass somewhere else in its own hierarchy.
A constant or a variable of a certain type may actually refer to an instance of subclass behind the scenes. If this is the case, using the typecast operator, we can downcast to that type.
Because down casting can fail, the type cast operator comes in two forms. as? gives an optional value of the type to which it is attempted to down cast to. as! downcasts and also force unrwaps the result as a single compound action.
as? to be used when we are not sure the downcast will succeed. as! to be used if we are sure the downcast will succeed.
e.g. is like below
if let triangle = shape as Triangle
{
triangle++
}
References:
Wednesday, October 7, 2015
Swift Functions - Basics I
fun is used to declare a function. A function declaration can have zero or more parameters, written as name:Type. the function return type is written after the name of the function after parameter list with ->
func greet(name:String, day:String) -> String
{
return “Hello \(name), today is \(day).”
}
We can call a function by following its name with a list of arguments in parentheses. The first argument need not have its name, the subsequent ones should have.
for e.g.
greet(“anna” day:”tuesday”)
Swift can have Function that return multiple values
func minmax(array:[Int]) -> (min:Int, max:Int)
{
return (5,10)
}
let bounds = minmax([5,6,7,8,9,10])
print ("min is \(bounds.min) and max is \(bounds.max)")
The return types can be optional also and optional return values is represented with ?
for e.e.g
func minmax(array:[Int]) -> (min:Int, max:Int) ?
{
return (currentMin, currentMax)
}
if (let bounds = minmax([1,2,3,4]))
{
print("min is :\(bounds.min) and max is: (bounds.max)")
}
There are lot more in functions!
references:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Functions.html
Monday, October 5, 2015
Essentials of Swift - Learning Part II
Control Flow:
There are two types of control flow statements
1. Conditional Statements => e.g If and switch
2. Loops => e.g. for-in and while
let number = 10
if number < 10
{
print (number is less than 10)
}
else if number > 100
{
print (number is greater than 100)
}
else
{
print(“number is between 10 and 100 ”)
}
We can use optional binding in an if statement to check whether an optional contains a value.
var optionalName:String ? = “Test”
if let tempStr = optionalName
{
print “optional name is \(tempStr)”
}
if optional value is nil, the condition becomes false and won’t execute.
We can use single if statement to bind multiple values. A where clause can be added to a case to further scope the conditional statement. In this case, if statement executes only if binding is successful for all of these values and all conditions are met.
let optionalHello : “hello”
let hello = optionalHello where hello.hasPrefix(“H”), let name = optionalName
{
greeting = “\(hello), \(name)”
}
Switches are powerful, A switch statement can support any kind of data type and a wide range of comparison operations - it isn’t limited to integers and test for equality.
let vegetable = “red pepper”
switch vegetable
{
case “celery” :
let vegetableComment = “Add some raisins and make ants on the log”
case “cucumber”, “watercress”:
let vegetableComment = “That would make good tea sanwitch”
case let x where x.hasPrefix(“bell”):
let vegetableComment = “Is it spicy \(x)?”
default:
let vegetableComment = “Everything tastes good in tea”
}
Notice that we don’t need to have a break here!
References:
Sunday, October 4, 2015
Git tutorial - Undoing changes
Git revert command undoes a committed snapshot. But instead of removing the commit from the project history, it figures out how to undo the changes introduced by the commit and appends a new commit with the resulting content . This prevents git from losing the history.
git revert
Git revert should be used if we want to revert entire commit from the project history. This can be useful for example when a bug was introduced by a particular commit. Instead of going ahead and fixing it manually, the revert command can be used to revert this change automatically.
git revert undoes only the one commit that it is asked to revert. It does not revert all of the subsequent commit that occurred after this. In git, this is called git reset. in git terminology, git revert is a safe way to undo a change while git reset is a dangerous method. when reset is done, there is no way to get back the original content, it removes all of them permanently unlike revert.
However, git reset is a versatile command in many ways. The git reset can be used to revert the changes in the staging area and the working directory. In other words, it should be only used to undo the changes in the local directory.
Some of the usages for the command include the below
git reset
This command removes the specified file from the staging area, but leaving the working directory unchanged. This upstages the file without overwriting any changes.
git reset
reset the staging area to match the most recent commit, but leaving the working directory unchanged. This upstages all files without overwriting any changes, giving the opportunity to re-build the staged snapshot from scratch.
git reset —-hard
resets the staging area and the working directory to match the most recent commit. In addition to upstaging the file, this —hard flag tells git to overwrite all the changes in the working directory too. In other words, it removes all the uncommitted changes too . to be used with caution
git reset move the current branch tip backward to commit. resets the staging area to match, but leaving the working directory alone. All changes made since commit will reside in the working drirectory, which lets us to re-commit the project history using cleaner more atomic snapshots.
another variant is git reset —hard
References:
https://www.atlassian.com/git/tutorials/undoing-changes/
Working With GCDAsyncSocket
One of the most powerful features of GCDAsyncSocket is its queued architecture. This allows to control the socket whenever it is convenient to the developer and not when the socket tells when it is ready.
For e.g the below method will return immediately and the delegate method didConnectToHost:port: will be invoked when the connection has completed.
[asyncSocket connectToHost:host onPort:port error:nil];
At this moment the connection is not yet established. It has internally just started the asynchronous connection attempt. However, AsyncSocket lets to reading / writing. Below method is going to queue the read request. After the connection is established, the read request will be automatically made.
[asyncSocket readDataToLength:LENGTH_HEADER withTiemout:TIMEOUT_NONE tag:TAG_HEADER];
In addition to it, we can also do multiple read/write.
[asyncSocket writeData:msgHeader withTimeout:TIMEOUT_NONE tag:TAG_HEADER];
//We don’t have to wait for the write to complete
[asyncSocket writeData:msgBody withTimeout:TIMEOUT_NONE tag:TAG_BODY];
References:
Subscribe to:
Posts (Atom)