Debug中常见错误之对象被提前释放&函数调用中selector传递机制一窥

一、大纲

1、SIGABRT错误以及出现“unrecognized selector sent to instance XXX”

2、程序中过早释放对象;

3、追到了几个牛逼的函数;

4、启示


二、下面依次说说

1、出现“unrecognized selector sent to instance XXX” 这条错误消息意味着你的app正在试着执行一个不存在的方法。这种情况的发生,主要是都是一个方法被错误的对象调用了(也就是这个对象没有这个方法,但是你调用了他,就错了)。这种错误的解决方法也比较简单,通过使用Exception Breakpoint(异常断点),你可以告诉xcode在一个特定的时候暂停这个程序,这样你就知道是在哪行代码上出现了这个错误,从而继续追踪到出错的对象和出错的selector;

2、这次出现这个SIGABRT错误的原因是我在引用一个第三方库TSTableView的时候没有注意到它在运行中一直需要保留其数据模型TSTableViewModel,而在我的程序中参照案例我只是在TSTableView的初始函数ViewDidLoad中实例化了它,但是并没有保留它,而在之后的操作中,由于还要用到这个Model,所以最后找不到它了,传递给它的selector就回头传递给TSTableView本身,只可惜TSTableView本身并不响应这个selector,最后就报出了"unrecognized selector sent to instance XXX"这样的错误;

3、在追踪的过程中,发现了TSTableView的两个非常厉害的函数:

    

#pragma mark - Provide TSTableViewDataSource functionality

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if(!signature)
        signature = [(id)self.dataSource methodSignatureForSelector:aSelector];
    
    return signature;
}

- (void)forwardInvocation:(NSInvocation *)anInvocation
{
    if ([self.dataSource respondsToSelector:[anInvocation selector]])
        [anInvocation invokeWithTarget:self.dataSource];
    else
        [super forwardInvocation:anInvocation];
}
     这是源代码,具体原理我也没去深究,简单讲一下我的理解,现在的情况是TSTableView本身没有实现一个叫做 TSTableViewDataSource的协议protocol,但是它的一个属性dataSource实现了这个协议,因此,当一个 TSTableViewDataSource协议中定义的selector传递到TSTableView的时候(这里比如说numberOfColumns),TSTableView会先调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector这个方法,判断它自己对这个selector有没有signature,如果没有就返回它的小弟,也就是dataSource属性对于此selector的signature,然后调用下面一个方法

- (void)forwardInvocation:(NSInvocation *)anInvocation,说白了这个方法做的事情也很简单,那就是先判断传递过来的selector自己搞不搞得定,搞得定的话就自己搞定,搞不定的话就让自己的小弟(也就是dataSource属性)出马来搞定。

4、启示

      刚开始遇到这个bug的时候自己都有点不知所措,因为我看了一下TSTableView的的确确是不能够响应numberOfColumns这个selector的啊,一时间我都怀疑是不是我下载的第三方库文件有问题,现在终于明白了,selector传递到一个对象的时候,即使表面上看,这个对象是不能响应的,但是这个对象可以通过selector传递的机制,将这个selector传递给其他对象来处理,我想这也是Objective-C语言的动态性的一种真真切切的体现吧。

    

`moodle-mod_hvp`是一个用于Moodle平台的交互式多媒体内容插件。其,`amd/src/embed.js`是该插件的一个JavaScript模块,主要用于在页面嵌入交互式多媒体内容。 该模块的代码如下: ```javascript define(['jquery', 'core/ajax', 'core/log'], function($, ajax, log) { var exports = {}; /** * Embed a H5P activity in the page. * * @param {string} selector The jQuery selector of the container element for the H5P activity. * @param {string} url The URL of the H5P activity. * @param {object} params Optional parameters for the H5P activity. * @param {function} callback Optional callback to call after embedding the H5P activity. */ exports.embed = function(selector, url, params, callback) { log.debug('Embedding H5P activity with URL: ' + url); // Load H5P library. require(['h5p'], function(H5P) { // Get the container element. var container = $(selector); // Check if container exists. if (container.length === 0) { log.warn('Cannot embed H5P activity. No container element found with selector: ' + selector); return; } // Build H5P options. var options = $.extend({}, params, { frameJs: url, frameCss: url.replace(/\.js$/, '.css'), ajaxPath: M.cfg.wwwroot + '/mod/hvp/ajax.php' }); // Embed H5P activity. H5P.externalDispatcher.on('xAPI', function(event) { var data = { action: 'xAPI', event: event.data.statement }; ajax.post(options.ajaxPath, data).done(function(response) { log.debug('xAPI statement sent successfully.'); }).fail(function() { log.warn('Failed to send xAPI statement.'); }); }); H5P.externalDispatcher.on('resize', function(event) { container.height(event.data.height); }); H5P.embed(selector, options); // Call callback function if provided. if (typeof callback === 'function') { callback(); } }); }; return exports; }); ``` 这段代码定义了一个JavaScript模块,其包含了一个名为`embed`的函数。该函数用于在页面嵌入H5P活动。具体来说,该函数接受四个参数: - `selector`:H5P活动的容器元素的jQuery选择器。 - `url`:H5P活动的URL。 - `params`:H5P活动的可选参数。 - `callback`:嵌入H5P活动后要调用的可选回调函数。 函数内部主要包含以下步骤: 1. 载入`jquery`、`core/ajax`和`core/log`模块。 2. 加载`h5p`库。 3. 获取容器元素。 4. 构建H5P选项。 5. 嵌入H5P活动。 6. 如果提供了回调函数,则调用它。 在H5P活动嵌入期间,该模块还会将xAPI语句发送到服务器,并在H5P活动大小更改时调整容器元素的高度。 总的来说,`moodle-mod_hvp`的`amd/src/embed.js`模块主要用于在Moodle平台上嵌入交互式多媒体内容,并实现了一些额外的功能,如xAPI语句发送和容器高度调整。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值