课程视频地址: http://edu.csdn.net/course/detail/1342/20992?auto_start=1

一. 什么是引用计数



引用计数是现代内存管理中经常使用到的一个概念,它的基本思想是通过计数方式实现多个不同对象同时引用一个共享对象,具体地讲,当创建一个对象的实例并在堆上分配内存时,对象的引用计数为1,在其他对象中需要持有这个共享对象时,需要把共享对象的引用计数加1,当其他对象不再持有该共享对象时,共享对象的引用计数减1,当共享对象的引用计数变成0时,对象的内存会被立即释放。

在Cocos2d-x中,则定义了retain,release和autorelease函数,分别用于增加计数、减少计数以及将一个对象交给自动释放池对象AutoreleasePool进行管理,由AutoreleasePool对象负责调用release函数。


二. Ref类



Ref类实现了引用计数的功能,它是引擎代码中绝大多数其他类的父类,定义在CCRef.h中,实现在CCRef.cpp中。其实在CCRef.h文件中不止定义了Ref类,还定义了Clonable类、一系列的宏定义和类型定义,不过我们暂且将精力放在Ref类的解读上。Ref类使用私有成员变量_referenceCount保存计数值,并通过retain,release和autorelease函数实现增减计数值。下面我们来看一下Ref类的代码,从源码进行分析,代码如下:

#ifndef __BASE_CCREF_H__
#define __BASE_CCREF_H__


#include "platform/CCPlatformMacros.h"
#include "base/ccConfig.h"
//内存泄露检测的开关
#define CC_REF_LEAK_DETECTION 0


NS_CC_BEGIN


class Ref;


/** Interface that defines how to clone an Ref */
//Clonable类定义了复制Ref类对象的规约,3.0以上版本建议使用clone函数,copy函数已属于废弃函数。
class CC_DLL Clonable
{
public:
    /** returns a copy of the Ref */
    //返回一个copy的Ref对象,纯虚函数,需要重写
    virtual Clonable* clone() const = 0;
    /**
     * @js NA
     * @lua NA
     */
    virtual ~Clonable() {};


    /** returns a copy of the Ref.
     * @deprecated Use clone() instead
     */
    //被废弃
    CC_DEPRECATED_ATTRIBUTE Ref* copy() const
    {
        // use "clone" instead
        CC_ASSERT(false);
        return nullptr;
    }
};


class CC_DLL Ref
{
public:
    
    //保留,引用计数+1
    void retain();


    //释放,引用计数-1
    void release();


    Ref* autorelease();


    //获得引用计数
    unsigned int getReferenceCount() const;


protected:
    
    Ref();


public:
    
    //析构
    virtual ~Ref();


protected:
    //引用的计数,retain 会 +1  release会 -1
    unsigned int _referenceCount;
    //设定CAutoreleasePool为友元类,这是一个通过CCObject指针容器CCMutableArray来对CCObject实例对象的内存进行管理的类,CCMutableArray在加入CCObject时对其引用计数器加1,在移除CCObject时对其引用计数器减1。
    friend class AutoreleasePool;


#if CC_ENABLE_SCRIPT_BINDING
public:
    // 唯一ID
    unsigned int        _ID;
    /// Lua reference id
    // 在LUA脚本引擎中的访问标识ID.暂可不理会,待学习到LUA时再分析
    int                 _luaID;
    //swift脚本的对象指针,为支持swift脚本所定义的
    void* _scriptObject;
#endif


#if CC_USE_MEM_LEAK_DETECTION
public:
    //打印内存泄露的信息
    static void printLeaks();
#endif
};


class Node;
//动作类的回调函数
typedef void (Ref::*SEL_CallFunc)();
typedef void (Ref::*SEL_CallFuncN)(Node*);
typedef void (Ref::*SEL_CallFuncND)(Node*,void*);
typedef void (Ref::*SEL_CallFuncO)(Ref*);
//menuitem的回调函数
typedef void (Ref::*SEL_MenuHandler)(Ref*);
//schedule的回调函数
typedef void (Ref::*SEL_SCHEDULE)(float);


#define CC_CALLFUNC_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFunc>(&_SELECTOR)
#define CC_CALLFUNCN_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncN>(&_SELECTOR)
#define CC_CALLFUNCND_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncND>(&_SELECTOR)
#define CC_CALLFUNCO_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_CallFuncO>(&_SELECTOR)
#define CC_MENU_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_MenuHandler>(&_SELECTOR)
#define CC_SCHEDULE_SELECTOR(_SELECTOR) static_cast<cocos2d::SEL_SCHEDULE>(&_SELECTOR)


// Deprecated
#define callfunc_selector(_SELECTOR) CC_CALLFUNC_SELECTOR(_SELECTOR)
#define callfuncN_selector(_SELECTOR) CC_CALLFUNCN_SELECTOR(_SELECTOR)
#define callfuncND_selector(_SELECTOR) CC_CALLFUNCND_SELECTOR(_SELECTOR)
#define callfuncO_selector(_SELECTOR) CC_CALLFUNCO_SELECTOR(_SELECTOR)
#define menu_selector(_SELECTOR) CC_MENU_SELECTOR(_SELECTOR)
#define schedule_selector(_SELECTOR) CC_SCHEDULE_SELECTOR(_SELECTOR)




// end of base_nodes group
/// @}


NS_CC_END


#endif // __BASE_CCREF_H__

Ref将构造函数声明为保护类型,防止直接生成Ref对象,在构造函数的成员初始化列表中将引用计数值_referenceCount初始化为1。retain函数将_referenceCount加1,release函数则减1,autorelease函数则将对象托管给AutoreleasePool对象进行管理,具体实现代码如下:


#include "base/CCRef.h"
#include "base/CCAutoreleasePool.h"
#include "base/ccMacros.h"
#include "base/ccScriptSupport.h"


#if CC_REF_LEAK_DETECTION
#include <algorithm>    // std::find
#endif


NS_CC_BEGIN


#if CC_REF_LEAK_DETECTION
static void trackRef(Ref* ref);
static void untrackRef(Ref* ref);
#endif


Ref::Ref()
: _referenceCount(1) // when the Ref is created,the reference count of it is 1
{
#if CC_ENABLE_SCRIPT_BINDING
    //定义一个静态UINT类型变量做为实例对象计数器,此值只会增长,不会减少,保证唯一。
    static unsigned int uObjectCount = 0;
    //脚本对象的Id
    _luaID = 0;
    //注意:所有由此CCObject类派生的子类也会拥有这个唯一的ID。它可以使我们通过唯一ID来获取相应的实例对象。
    _ID = ++uObjectCount;
    _scriptObject = nullptr;
#endif
    
#if CC_REF_LEAK_DETECTION
    //加入到保存Ref的list中
    trackRef(this);
#endif
}


Ref::~Ref()
{
#if CC_ENABLE_SCRIPT_BINDING
    // if the object is referenced by Lua engine,remove it
    //如果这个对象被lua脚本引擎引用了,就删除掉
    if (_luaID)
    {
        ScriptEngineManager::getInstance()->getScriptEngine()->removeScriptObjectByObject(this);
    }
    else
    {
        //获得脚本引擎
        ScriptEngineProtocol* pEngine = ScriptEngineManager::getInstance()->getScriptEngine();
        //如果这个脚本引擎是javascript
        if (pEngine != nullptr && pEngine->getScriptType() == kScriptTypeJavascript)
        {
            //删除对象
            pEngine->removeScriptObjectByObject(this);
        }
    }
#endif




#if CC_REF_LEAK_DETECTION
    //从保存Ref的list中删除
    if (_referenceCount != 0)
        untrackRef(this);
#endif
}


void Ref::retain()
{
    CCASSERT(_referenceCount > 0,"reference count should greater than 0");
    //引用计数+1
    ++_referenceCount;
}


void Ref::release()
{
    CCASSERT(_referenceCount > 0,"reference count should greater than 0");
    //引用计数-1
    --_referenceCount;


    if (_referenceCount == 0)
    {
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
        auto poolManager = PoolManager::getInstance();
        if (!poolManager->getCurrentPool()->isClearing() && poolManager->isObjectInPools(this))
        {
            
            CCASSERT(false,"The reference shouldn't be 0 because it is still in autorelease pool.");
        }
#endif


#if CC_REF_LEAK_DETECTION
        //从保存Ref*的list中删除
        untrackRef(this);
#endif
        delete this;
    }
}


Ref* Ref::autorelease()
{
    //调用内存管理器实例对象的addobject函数加入当前Ref实例对象的指针
    PoolManager::getInstance()->getCurrentPool()->addobject(this);
    return this;
}


unsigned int Ref::getReferenceCount() const
{
    //返回该对象的引用计数
    return _referenceCount;
}


#if CC_REF_LEAK_DETECTION
//创建保存Ref对象的list
static std::list<Ref*> __refAllocationList;


void Ref::printLeaks()
{
    // Dump Ref object memory leaks
    //如果是空的不做处理
    if (__refAllocationList.empty())
    {
        log("[memory] All Ref objects successfully cleaned up (no leaks detected).\n");
    }
    else    //不为空
    {
        //打印__refAllocationList的长度
        log("[memory] WARNING: %d Ref objects still active in memory.\n",(int)__refAllocationList.size());
        //循环打印Ref对象的信息
        for (const auto& ref : __refAllocationList)
        {
            CC_ASSERT(ref);
            const char* type = typeid(*ref).name();
            log("[memory] LEAK: Ref object '%s' still active with reference count %d.\n",(type ? type : ""),ref->getReferenceCount());
        }
    }
}


static void trackRef(Ref* ref)
{
    CCASSERT(ref,"Invalid parameter,ref should not be null!");


    // Create memory allocation record.
    //把ref对象添加到list中
    __refAllocationList.push_back(ref);
}


static void untrackRef(Ref* ref)
{
    //获得ref的迭代器
    auto iter = std::find(__refAllocationList.begin(),__refAllocationList.end(),ref);
    //如果没找到
    if (iter == __refAllocationList.end())
    {
        log("[memory] CORRUPTION: Attempting to free (%s) with invalid ref tracking record.\n",typeid(*ref).name());
        return;
    }
    //从list中释放ref
    __refAllocationList.erase(iter);
}


#endif // #if CC_USE_MEM_LEAK_DETECTION




NS_CC_END




我们看到Ref其实真的很单纯,它主要就是有两个功能,一个是提供引用计数增减的方法。一个是通过引用计数交给内存管理器进行内存管理。下面我们来重点看一下autorelease函数的意义,顾名思义,“自动释放”。也就是说调用此函数则当前CCObject实例对象不需要用户在外部去手动调用release进行内存的释放工作。我们已经知道它通过引用计数来处理在什么时候内存释放。Cocos2d-x是怎么做到的呢?

在autorelease函数中有这么一句

//调用内存管理器实例对象的addobject函数加入当前Ref实例对象的指针

PoolManager::getInstance()->getCurrentPool()->addobject(this);

PoolManager代表了内存管理器。此句调用PoolManager的实例对象获得AutoreleasePool对象,然后调用AutoreleasePool的addobject函数将当前Ref对象的指针交给内存管理器。下面我们就来看看这辆类的实现。


三. PoolManager和AutoreleasePool



内存管理器主要用来管理Cocos2d-x内存自动释放的,在Cocos2d-x的内存管理中起到了重要的作用,下面我们通过AutorelesePool和PoolManager两个类的代码来分析一下Ccocos2d-x内存管理的原理。首先我们来看一下CCAutoreleasePool.h:


#ifndef __AUTORELEASEPOOL_H__
#define __AUTORELEASEPOOL_H__


#include <vector>
#include <string>
#include "base/CCRef.h"


NS_CC_BEGIN


class CC_DLL AutoreleasePool
{
public:
    //构造
    AutoreleasePool();
    //通过name进行构造
    AutoreleasePool(const std::string &name);
    
    /**
     * @js NA
     * @lua NA
     */
    //析构
    ~AutoreleasePool();
    //添加Ref
    void addobject(Ref *object);


    //清除
    void clear();
    
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    //判断是否执行了clear()操作
    bool isClearing() const { return _isClearing; };
#endif
    
    //检查是否有object对象
    bool contains(Ref* object) const;
    //打印删除的对象的地址
    void dump();
    
private:
    //ref对象保存
    std::vector<Ref*> _managedobjectArray;
    //autoreleasepool的名字
    std::string _name;
    
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
   
    //是否执行清除操作的
    bool _isClearing;
#endif
};


class CC_DLL PoolManager
{
public:
  
    CC_DEPRECATED_ATTRIBUTE static PoolManager* sharedPoolManager() { return getInstance(); }
    //获得poolManager的实例
    static PoolManager* getInstance();
    
    
    CC_DEPRECATED_ATTRIBUTE static void purgePoolManager() { destroyInstance(); }
    //销毁
    static void destroyInstance();
    
    
    //获得当前的autoreleasepooll
    AutoreleasePool *getCurrentPool() const;
    //判断obj是否在autoreleasepool
    bool isObjectInPools(Ref* obj) const;


    /**
     * @js NA
     * @lua NA
     */
    //把AutoreleasePool设置成友元类
    friend class AutoreleasePool;
    
private:
    //构造
    PoolManager();
    //析构
    ~PoolManager();
    //加入
    void push(AutoreleasePool *pool);
    //弹出
    void pop();
    //poolmanager的实例
    static PoolManager* s_singleInstance;
    //保存AutoreleasePool对象的vector
    std::vector<AutoreleasePool*> _releasePoolStack;
};


// end of base_nodes group
/// @}


NS_CC_END


#endif //__AUTORELEASEPOOL_H__



从CCAutoreleasePool.h中可以看到声明了两个类,分别是AutoreleasePool,PoolManager,AutoreleasePool主要用来管理Ref对象,而PoolManager主要用来管理AutoreleasePool,具体这两个类是怎么实现的呢,我们来看看CCAutoreleasePool.cpp的代码:

#include "base/CCAutoreleasePool.h"
#include "base/ccMacros.h"


NS_CC_BEGIN


AutoreleasePool::AutoreleasePool()
: _name("") //设置名字为""
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0),_isClearing(false) //设置_isClearing为false
#endif
{
    //申请vector的size增加150
    _managedobjectArray.reserve(150);
    //把该autoreleasePool添加到管类类
    PoolManager::getInstance()->push(this);
}


AutoreleasePool::AutoreleasePool(const std::string &name)
: _name(name)   //设置名称
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0),_isClearing(false)    //设置_isClearing
#endif
{
    //申请vector的size增加150
    _managedobjectArray.reserve(150);
    //把该autoreleasePool添加到管类类
    PoolManager::getInstance()->push(this);
}


AutoreleasePool::~AutoreleasePool()
{
    cclOGINFO("dealLocing AutoreleasePool: %p",this);
    //清除
    clear();
    //弹出
    PoolManager::getInstance()->pop();
}


void AutoreleasePool::addobject(Ref* object)
{
    //把object添加到_managedobjectArray
    _managedobjectArray.push_back(object);
}


void AutoreleasePool::clear()
{
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = true; //设置为执行了清空操作
#endif
    //遍历_managedobjectArray所有的Ref
    for (const auto &obj : _managedobjectArray)
    {
        //调用obj的release,对obj的引用计数-1
        obj->release();
    }
    //清空_managedobjectArray
    _managedobjectArray.clear();
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
    _isClearing = false;  //设置为未执行了清空操作
#endif
}


bool AutoreleasePool::contains(Ref* object) const
{
    //遍历_managedobjectArray
    for (const auto& obj : _managedobjectArray)
    {
        //如果相等
        if (obj == object)
            //返回true,表示_managedobjectArray中有该对象
            return true;
    }
    return false;
}


void AutoreleasePool::dump()
{
    //打印_managedobjectArray的size,用于调试
    cclOG("autorelease pool: %s,number of managed object %d\n",_name.c_str(),static_cast<int>(_managedobjectArray.size()));
    cclOG("%20s%20s%20s","Object pointer","Object id","reference count");
    for (const auto &obj : _managedobjectArray)
    {
        CC_UNUSED_ParaM(obj);
        //打印对象的引用计数
        cclOG("%20p%20u\n",obj,obj->getReferenceCount());
    }
}




//--------------------------------------------------------------------
//
// PoolManager
//
//--------------------------------------------------------------------
//设置PoolManager的单例对象为nullptr
PoolManager* PoolManager::s_singleInstance = nullptr;


PoolManager* PoolManager::getInstance()
{
    //判断是否存在s_singleInstance
    if (s_singleInstance == nullptr)
    {
        //如果s_singleInstance为nullptr,new一个PoolManager
        s_singleInstance = new (std::nothrow) PoolManager();
        // Add the first auto release pool
        //new一个AutoreleasePoll并取名字为cocos2d autorelease pool
        new AutoreleasePool("cocos2d autorelease pool");
    }
    return s_singleInstance;
}


void PoolManager::destroyInstance()
{
    //删除s_singleInstance
    delete s_singleInstance;
    s_singleInstance = nullptr;
}


PoolManager::PoolManager()
{
    //增加_releasePoolStack容器的size
    _releasePoolStack.reserve(10);
}


PoolManager::~PoolManager()
{
    cclOGINFO("dealLocing PoolManager: %p",this);
    
    while (!_releasePoolStack.empty())
    {
        //获得最后一个AutoreleasePool
        AutoreleasePool* pool = _releasePoolStack.back();
        //删除
        delete pool;
    }
}




AutoreleasePool* PoolManager::getCurrentPool() const
{
    //获得当前的AutoreleasePool
    return _releasePoolStack.back();
}


bool PoolManager::isObjectInPools(Ref* obj) const
{
    //遍历所有的AutoreleasePool
    for (const auto& pool : _releasePoolStack)
    {
        //如果pool中存在obj,返回true
        if (pool->contains(obj))
            return true;
    }
    return false;
}


void PoolManager::push(AutoreleasePool *pool)
{
    //把AutoreleasePool添加到_releasePoolStack
    _releasePoolStack.push_back(pool);
}


void PoolManager::pop()
{
    CC_ASSERT(!_releasePoolStack.empty());
    //删除当前的AutoreleasePool
    _releasePoolStack.pop_back();
}


NS_CC_END



看完上面的代码,大家是不是有点晕啊,下面我来总结一下,首先Autorelease提供了_managedobjectArray的vector容器来保存Ref对象,通过对_managedobjectArray的添加,删除来实现Ref的添加和删除。
通过PoolManager来管理AutoreleasePool,通过PoolManager的pop,push来完成对AutoreleasePool增减,通过clear来实现AutoReleasePool的成员Ref的删除。
看完解释你可能还有一个疑问,说了这么多,那么Cocos2d-x是如果通过调用PoolMananger的相关方法来管理内存的呢,带着这个疑问我们来看看下一个知识点。


四.Cocos2d-x内存管理的运行原理



还记得我们之前讲的渲染流程吗,从Application类的run()方法开始,一直完成了整个渲染流程的介绍,那么内存管理的入口在哪儿了,聪明的你可能已经猜到了,没错也是在Application类的run()方法,下面我们通过Cocos2d-x的源码来看一下如何调用到PoolManager的,首先打开Application的run()方法,在run()方法中我们可以看到如下代码:
director->mainLoop();
该代码调用了mainLoop()方法,该方法就是Cocos2d-x的住循环的方法,每帧都会被调用一次。进入该方法,我们可以看到如下代码:
PoolManager::getInstance()->getCurrentPool()->clear();
在mainLoop中调用了PoolManager获得当前的AutoreleasePool的clear()方法中调用存放在AutoreleasePool中的所有对象release()方法,在release()中首先对Ref对象的引用计数-1,如果引用计数为0那么就delete掉该对象。
看完上面说的一大堆小编,大家是不是已经有点晕了,下面我们通过一个实例来看看:
//创建一个Node,create方法会对node的引用计数+1,并在create方法中调用了node的autorelease方法,把它加入到了自动释放池
Node* node = Node::create();
//把Node添加到Layer上,addChild操作会对node的引用计数+1
this->addChild(node);
通过代码注释我们可以得出,现在node的引用计数为2,接着随着在mainLoop的
PoolManager::getInstance()->getCurrentPool()->clear();
的调用,我们对所有的Ref的引用计数进行了-1操作,当然我们的node对象也执行了改操作,那么我们的node对象的引用计数就变成了 1,接着对node进行了addchild的操作,在addchild中其实对要添加的对象进行了retain操作,所以addChil操作之后node的引用计数变成了2.然后随着在mainloop中调用 AutoreleasePool的clear()方法之后,node的引用计数就减一了,同时把保存该node的_managedobjectArray进行了clear()操作,也是说把node从AutoreleasePool的managedobjectArray中进行了清除操作,所以在mainloop中在下一次执行AutoreleasePool的clear()的时候不会再次对node进行release操作,所以node的引用计数会一直为1,只用当调用node的remove()方法的时候,才会对node的进行release操作,release操作首先对其引用计数-1,那么node的引用计数就变成了0,然后就会delete掉改node对象,也就完成了node的自动释放释放。


可能大家会感觉有点绕,但是通过配合源码来仔细研读这段话,相信让你对Cocos2d-x的内存管理有个新的认识的。


五.Cocos2d-x内存管理总结



本节课主要讲解了Cocos2d-x内存管理,我们通过源码的解析了解了Cocos2d-x内存管理的原理,并通过node的创建的例子来学习了内存管理。Cocos2d-x内存管理是一个比较难的概念,在平时工作中只有理解了Cocos2d-x的内存管理的原理,才能更好的使用它,因为我们的每个Cocos2d-x的内置类都是通过它来进行管理的。


六.作业:

仔细研读Ref,AutoreleasePool,PoolManager三个类的源码。

Cocos2d-x从入门到精通第七课《内存管理》的更多相关文章

  1. 利用Node实现HTML5离线存储的方法

    这篇文章主要介绍了利用Node实现HTML5离线存储的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式)

    这篇文章主要介绍了Html5 Canvas实现图片标记、缩放、移动和保存历史状态功能 (附转换公式),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. ios – 仅在异步函数完成执行后运行代码

    所以,例如:如果问题是你不知道要调用什么函数,你可以配置你周围的函数/对象,这样有人可以给你一个函数,然后你在我上面说“调用函数”的地方调用你的函数.例如:

  4. ios – 如何使用Objective C类中的多个参数调用Swift函数?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. ios – 使用带有NodeJs HTTPS的certificates.cer

    我为IOS推送通知生成了一个.cer文件,我希望将它与NodeJSHTTPS模块一起使用.我发现HTTPS模块的唯一例子是使用.pem和.sfx文件,而不是.cer:有解决方案吗解决方法.cer文件可以使用两种不同的格式进行编码:PEM和DER.如果您的文件使用PEM格式编码,您可以像使用任何其他.pem文件一样使用它(有关详细信息,请参见Node.jsdocumentation):如果您的文件使

  6. iOS 7,用于断开调用的私有API CTCallDisconnect不起作用

    谢谢!

  7. ios – 监控CBPeripheral状态变化

    我在CoreBluetooth库中找不到任何暴露的东西,我想在CBperipheralstate发生变化时调用一个函数.现在我只有一个switch语句来检查外设状态,但它总是只返回连接或断开连接.我如何进入连接/断开连接的情况?

  8. 处理内存管理和iOS Cordova项目?

    任何人都可以告诉我如何处理基于iOSCordova的项目中的内存管理“收到内存警告”当我在iPhone或iPad上运行时,我在iOSCordova项目中收到此警告.我在我的应用程序中使用CDVlocation进行地理定位.我主要是在加载基于地图的视图时收到此消息.我正在使用基于ARC的Xcode项目任何帮助管理内存警告与cordova“收到内存警告”将不胜感激.谢谢你们解决方法在CDVPlugin.m中尝试这种方式

  9. ios – Xcode游乐场不执行功能

    我创建了一个新的游乐场,我添加了简单的功能,但该功能从未被调用过:你们中的任何人都知道为什么函数没有被调用?我真的很感谢你的帮助解决方法因为你没有调用该函数.只需称呼它:

  10. ios – Swift中没有输入参数的通用函数?

    我有一个通用的Swift函数,如下所示:编译器没有错误,但我不知道如何调用此函数.我试过了:但它不起作用.如何在没有输入参数的情况下在Swift中调用Generic函数?解决方法你需要通过一些调用上下文告诉Swift返回类型是什么:注意,在后一种情况下,只有当someCall采用类似于Any的模糊类型作为其参数时,才需要这样做.相反,someCall被指定为[Int]作为参数,函数本身提供上下文,你可以只写someCall事实上,有时可以非常推断出背景!

随机推荐

  1. 【cocos2d-x 3.x 学习笔记】对象内存管理

    Cocos2d-x的内存管理cocos2d-x中使用的是上面的引用计数来管理内存,但是又增加了一些自己的特色。cocos2d-x中通过Ref类来实现引用计数,所有需要实现内存自动回收的类都应该继承自Ref类。下面是Ref类的定义:在cocos2d-x中创建对象通常有两种方式:这两中方式的差异可以参见我另一篇博文“对象创建方式讨论”。在cocos2d-x中提倡使用第二种方式,为了避免误用第一种方式,一般将构造函数设为protected或private。参考资料:[1]cocos2d-x高级开发教程2.3节[

  2. 利用cocos2dx 3.2开发消灭星星六如何在cocos2dx中显示中文

    由于编码的不同,在cocos2dx中的Label控件中如果放入中文字,往往会出现乱码。为了方便使用,我把这个从文档中获取中文字的方法放在一个头文件里面Chinese.h这里的tex_vec是cocos2dx提供的一个保存文档内容的一个容器。这里给出ChineseWords,xml的格式再看看ChineseWord的实现Chinese.cpp就这样,以后在需要用到中文字的地方,就先include这个头文件然后调用ChineseWord函数,获取一串中文字符串。

  3. 利用cocos2dx 3.2开发消灭星星七关于星星的算法

    在前面,我们已经在GameLayer中利用随机数初始化了一个StarMatrix,如果还不知道怎么创建星星矩阵请回去看看而且我们也讲了整个游戏的触摸事件的派发了。

  4. cocos2dx3.x 新手打包APK注意事项!

    这个在编译的时候就可以发现了比较好弄这只是我遇到的,其他的以后遇到再补充吧。。。以前被这两个问题坑了好久

  5. 利用cocos2dx 3.2开发消灭星星八游戏的结束判断与数据控制

    如果你看完之前的,那么你基本已经拥有一个消灭星星游戏的雏形。开始把剩下的两两互不相连的星星消去。那么如何判断是GameOver还是进入下一关呢。。其实游戏数据贯穿整个游戏,包括星星消除的时候要加到获得分数上,消去剩下两两不相连的星星的时候的加分政策等,因此如果前面没有做这一块的,最好回去搞一搞。

  6. 利用cocos2dx 3.2开发消灭星星九为游戏添加一些特效

    needClear是一个flag,当游戏判断不能再继续后,这个flag变为true,开始消除剩下的星星clearSumTime是一个累加器ONE_CLEAR_TIME就是每颗星星消除的时间2.连击加分信息一般消除一次星星都会有连击信息和加多少分的信息。其实这些combo标签就是一张图片,也是通过控制其属性或者runAction来实现。源码ComboEffect.hComboEffect.cpp4.消除星星粒子效果消除星星时,为了实现星星爆裂散落的效果,使用了cocos2d提供的粒子特效引擎对于粒子特效不了

  7. 02 Cocos2D-x引擎win7环境搭建及创建项目

    官网有搭建的文章,直接转载记录。环境搭建:本文介绍如何搭建Cocos2d-x3.2版本的开发环境。项目创建:一、通过命令创建项目前面搭建好环境后,怎样创建自己的Cocos2d-x项目呢?先来看看Cocos2d-x3.2的目录吧这就是Cocos2d-x3.2的目录。输入cocosnew项目名–p包名–lcpp–d路径回车就创建成功了例如:成功后,找到这个项目打开proj.win32目录下的Hello.slnF5成功了。

  8. 利用cocos2dx 3.2开发消灭星星十为游戏添加音效项目源码分享

    一个游戏,声音也是非常的重要,其实cocos2dx里面的简单音效引擎的使用是非常简单的。我这里只不过是用一个类对所有的音效进行管理罢了。Audio.hAudio.cpp好了,本系列教程到此结束,第一次写教程如有不对请见谅或指教,谢谢大家。最后附上整个项目的源代码点击打开链接

  9. 03 Helloworld

    程序都有一个入口点,在C++就是main函数了,打开main.cpp,代码如下:123456789101112131415161718#include"main.h"#include"AppDelegate.h"#include"cocos2d.h"USING_NS_CC;intAPIENTRY_tWinMain{UNREFERENCED_ParaMETER;UNREFERENCED_ParaMETER;//createtheapplicationinstanceAppDelegateapp;return

  10. MenuItemImage*图标菜单创建注意事项

    学习cocos2dx,看的是cocos2d-x3.x手游开发实例详解,这本书错误一大把,本着探索求知勇于发现错误改正错误的精神,我跟着书上的例子一起调试,当学习到场景切换这个小节的时候,出了个错误,卡了我好几个小时。

返回
顶部