注:本文为作者原创,其中知识内容出自闪电终结者的视频课程
首先要强调一点,因为网络访问与Cocos的线程是不同的,网络访问需要自己的子线程(网络请求是需要时间的),所以在写代码时候无法将发生请求和请求数据写在一起,会导致无法请求到正确的数据,所以需要将请求数据之后调用的方法写在一个函数中,使用httpRequest类的setResponseCallback()函数来指定方法。
进入正题
上次把创建请求之类的都放在init()里,其实是不好的,如果会有多次请求,就需要创建多次HttpRequest对象
所以封装一个NetworkRequest类来实现
// NetworkRequest.hpp
#include <network/httpClient.h>
#include <string>
#include <functional>
class NetworkRequest {
// url地址
std::string url;
// 表单数据,可有可无
std::string postData;
// 请求对象
cocos2d::network::HttpRequest *request;
// 数据请求之后调用的方法
void networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response);
public:
NetworkRequest(const std::string &url, const std::string &postData = "");
// 实例化一个对象时候,如果需要立刻执行网络请求,则把send()写入构造函数里
virtual ~NetworkRequest();
// 发生请求
void send();
};
// NetworkRequest.cpp
#include "NetworkRequest.hpp"
NetworkRequest::NetworkRequest(const std::string &url, const std::string &postData): url(url), postData(postData) {
// 把创建请求放入构造函数里,不需要每次都创建这个模型(request),只要每次send不同模型(request)就行
request = new cocos2d::network::HttpRequest;
request -> setUrl(url.c_str());
if (postData == "") {
// 没有表单时候,只送数据即可
request -> setRequestType(cocos2d::network::HttpRequest::Type::GET);
} else {
request -> setRequestType(cocos2d::network::HttpRequest::Type::POST);
request -> setRequestData(postData.c_str(), postData.length());
}
// 设置这个请求与函数networkRequestCallBack连接,当收到服务器返回的数值时,调用该函数
request -> setResponseCallback(CC_CALLBACK_2(NetworkRequest::networkRequestCallBack, this));
}
void NetworkRequest::send() {
cocos2d::network::HttpClient::getInstance() -> send(request);
// 在真正使用完之后,request会被清除
request -> release();
}
void NetworkRequest::networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response){
}
NetworkRequest::~NetworkRequest() {}
现在唯一空着的是networkRequestCallBack函数,客户端需要对方法进行重构,在这里需要提供一个接口来完成该功能
- 法一:成员变量的解决方法,不推荐
- 法二:代理设计模式解决方法
代理模式
协议protocol:作为代理或者数据源要使用的方法
设计思路:
1.首先需要创建一个协议,如果要成为网络请求对象,则必须要实现协议中这个callBack方法
// 网络请求代理协议
class NetworkRequestDelegate {
public:
// 如果要成为网络请求对象,则必须要实现协议中这个callBack方法
// 声明为纯虚函数,因为此类是抽象类不能创建对象,考虑到继承的多态,用纯虚函数
virtual void networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response) = 0;
};
2.在networkRequest类中创建一个代理,这个代理遵守着NetworkRequestDelegate中的协议,代理可以在此类中调用遵守协议的方法
// 在networkRequest类中,声明一个代理对象(一个遵守协议的对象,此时就是TrandferTextScene)
NetworkRequestDelegate *delegate;
// cpp文件中,实现networkRequestCallBack函数
void NetworkRequest::networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response){
// 当代理不为空时,调用遵守的方法。
if(delegate) {
delegate -> networkRequestCallBack(sender, response);
}
}
3.修改主场景的代码
主场景想要实现网络访问,必须遵守网络请求代理协议,实现networkRequestCallBack这个函数,
// TransferTestScene.hpp
class TransferTestScene : public cocos2d::Layer, public NetworkRequestDelegate { // 遵守网络请求代理协议
public:
virtual bool init();
static cocos2d::Scene *createScene();
CREATE_FUNC(TransferTestScene);
private:
void button1Click(cocos2d::Ref *sender, cocos2d::ui::Widget::TouchEventType type);
cocos2d::Node *rootNode;
// 遵守协议,实现该函数
void networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response);
};
在cpp中实现该函数(当请求数据时候的调用方法):
void TransferTestScene::networkRequestCallBack(cocos2d::network::HttpClient *sender, cocos2d::network::HttpResponse *response) {
if (!response -> isSucceed()) return;
auto buffer = response -> getResponseData();
std::string str(buffer -> begin(), buffer -> end());
std::cout << str << std::endl;
}
4.修改客户端
创建一个NetworkRequest对象,!!然后把对象的代理设为自己,在发送内部已创建封装好的httpRequest对象。
auto nq = new NetworkRequest("http://127.0.0.1/phptext.php","username=h11213&password=p231");
即把NetworkRequest对象的代理设为自己,自己遵守着协议可以成为NetworkRequest对象的代理(决定着回调函数),
nq -> delegate = this;
nq -> send();
调试过程出现的问题
我用的编译器是xcode,
问题:在调试过程中出现连接问题
原因:构造函数的参数名写错了,导致在创建新的对象时候产生连接错误
这也许是个Xcode的Bug没有给提示,以后要注意了,这种小错误写代码时候就要保证没有。