Recently I am porting an app to cocos2d-x which I made for android, ios, bada, and qnx.
And realized that there is no simple way to get json object asynchronously.
So here, I am posting a class I have made. Please give me a feedback if there are some errors. Thank you.
CCNetwork.h
#include "cocos2d.h" #include "stdio.h" #include "stdlib.h" #include "curl.h" #include "pthread.h" #include "cJSON.h" namespace cocos2d{ class CCNetwork : public CCObject { SEL_CallFunc callback; SelectorProtocol *target; pthread_t threadInfo; char url[260]; cJSON *cJSONResult; CCNetwork() { cJSONResult = NULL; } protected: static size_t writer( char *data, size_t size, size_t nmemb, string *writerData ) { if(writerData == NULL) return 0; writerData->append(data, size * nmemb); return size * nmemb; } public: virtual ~CCNetwork() { if( cJSONResult != NULL ) { freeResultJSON(); } } static void *run( void *arg ) { CCNetwork *network = (CCNetwork *)arg; CURL *curl; CURLcode res; int result = 1; string buffer; network->cJSONResult = NULL; curl_global_init( CURL_GLOBAL_ALL ); curl = curl_easy_init(); if( curl ) { curl_easy_setopt( curl, CURLOPT_URL, network->url ); curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1L ); curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, CCNetwork::writer ); curl_easy_setopt( curl, CURLOPT_WRITEDATA, &buffer ); res = curl_easy_perform( curl ); curl_easy_cleanup( curl ); if (res == 0) { network->cJSONResult = cJSON_Parse( buffer.c_str() ); if( network->cJSONResult != NULL ) result = 0; } } ((network->target)->*(network->callback))(); return (void *)result; } cJSON *getResultJSON() { int success; if( pthread_join( threadInfo, (void **)&success ) == 0 ) return cJSONResult; else return NULL; } void freeResultJSON() { if( cJSONResult != NULL ) { cJSON_Delete( cJSONResult ); cJSONResult = NULL; } } static CCNetwork *loadJSON( const char *url, SelectorProtocol *target, SEL_CallFunc callback ) { CCNetwork *network = new CCNetwork(); if( network != NULL ) { network->target = target; network->callback = callback; strcpy( network->url, url ); if( pthread_create( &network->threadInfo, NULL, CCNetwork::run, network ) == 0 ) { network->autorelease(); return network; } CC_SAFE_DELETE( network ); } return NULL; } };}
callback function
void dataArrived() { isThreadRunning = false; }
the part which request url
isThreadRunning = true;scheduleUpdate();network = CCNetwork::loadJSON( "http://dodgemissile2.appspot.com/?count=10", this, callfunc_selector( YourNode::dataArrived ) );network->retain();
update function
void YourNode::update( ccTime dt ){ if( !isThreadRunning ) { if( network != NULL ) { cJSON *result = network->getResultJSON(); // process with result here network->release(); } unscheduleUpdate(); }}
RE: CCNetwork - any suggestions and comments are welcome :) - Added byWalzer Wang about 1 month ago
It will be a very useful class.
My suggestions when reviewing the code.
1. char url[260];
is danger, especially you dont' check the length before strcpy( network->url, url ), stack will easily overflow. I prefer to use std::string here to make it safe.
2. You like to use several return points in a function. It's not good when you would like to write some profile and test the performance. For example:
static size_t writer( char *data, size_t size, size_t nmemb, string *writerData ) { if(writerData == NULL) return 0; writerData->append(data, size * nmemb); return size * nmemb; }
The recommended approach is
static size_t writer( char *data, size_t size, size_t nmemb, string *writerData ) { // profile_start size_t retValue = 0; if(writerData != NULL) { writerData->append(data, size * nmemb); retValue = size * nmemb; } // profile_end. You have only one return point now return retValue; }