makeObjectsPerformSelector的使用

本文介绍了一个使用NSArray类方法makeObjectsPerformSelector进行批量操作的实例,该方法可以高效地对数组中的每个对象执行相同的操作,例如设置同一属性值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NSArray 类定义的方法:

makeObjectsPerformSelector:
这是数组用的方法,类似于for循环。

makeObjectsPerformSelector:@selector(method:)

意为数组中的每个元素都执行method方法

makeObjectsPerformSelector:@selector(method:) withObject:obj

表示数组中的每个元素都执行method方法,并把obj对象作为参数传到method方法中。

注意: 

这是 NSArray和NSSet的两个方法,相信大家很少用,它类似于 for循环,但有效率高于for循环

makeObjectsPerformSelector:类似于NSNotifation机制,并发的执行同一件事,不能像for循环那样区别对待

所以参数 argument 必须是非基本类型 ,如果要是用基本类型 请转换程 NSNumber 或者NSValue。

 

用法:如果一个数组objArr中存储了一组有hide属性的对象,需要将数组里所有对象的hide全部赋值为真,就可以这么写:

    [self.dataAray makeObjectsPerformSelector:@selector(setHidden:) withObject:@(NO)];
    [self.dataAray makeObjectsPerformSelector:@selector(setHidden:)];

代码如下:

//
//  ViewController.m
//  Demo1
//
//  Created by 思 彭 on 2017/4/6.
//  Copyright © 2017年 思 彭. All rights reserved.
//

#import "ViewController.h"
#import "Model.h"

@interface ViewController ()

@property (nonatomic, strong) NSArray *dataAray;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableArray *array = [NSMutableArray array];
    for (NSInteger i = 0; i < 10; i++) {
        Model *model = [[Model alloc]init];
        model.hidden = YES;
        [array addObject:model];
    }
    self.dataAray = [array copy];
    
    NSLog(@"变换前的model:");
    for (Model *model in self.dataAray) {
        NSLog(@"%d",model.hidden);
    }
    UIButton *button = [UIButton buttonWithType: UIButtonTypeCustom];
    button.frame = CGRectMake(100,100,100,50);
    button.layer.borderColor = [UIColor lightGrayColor].CGColor;
    button.layer.borderWidth = 0.5;
    [button setTitle:@"变换" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
    button.titleLabel.font = [UIFont systemFontOfSize:14];
    [button addTarget:self action:@selector(buttonDidClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}

- (void)buttonDidClick {
//    [self.dataAray makeObjectsPerformSelector:@selector(setHidden:) withObject:@(NO)];
    [self.dataAray makeObjectsPerformSelector:@selector(setHidden:)];
    NSLog(@"变换后的model:");
    for (Model *model in self.dataAray) {
        NSLog(@"%d",model.hidden);
    }
}

@end

 

//
//  Model.h
//  Demo1
//
//  Created by 思 彭 on 2017/4/6.
//  Copyright © 2017年 思 彭. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Model : NSObject

@property (nonatomic, assign) BOOL hidden;

@end

实现效果打印如下:

这种方式还是很快捷呀,不过还是有局限...

转载于:https://www.cnblogs.com/pengsi/p/6672345.html

<think>我们正在处理一个关于在UITableViewCell中正确注册BUNativeAd并处理点击事件以避免复用后仍响应广告的问题。 根据引用[1]和[3],我们知道自定义视图应该添加到UITableViewCell的contentView上。同时,广告的注册和点击事件处理需要特别注意,因为cell会被复用,如果不正确处理,复用后的cell可能会错误地响应之前的广告事件。 问题描述:在使用`[BUNativeAd registerContainer:withClickableViews:]`方法注册广告容器和可点击视图(例如ViewA)时,发现当cell被复用时,`unregisterView`方法无效,导致广告点击事件仍然被触发。 解决思路: 1. 我们需要在cell复用的时候(比如在`prepareForReuse`方法中)取消当前广告的注册,以避免复用后的cell仍然响应之前广告的点击事件。 2. 正确注册广告视图,确保每次使用cell时,广告视图都是重新绑定到新的广告数据。 步骤: 1. 在自定义的UITableViewCell中,提供一个配置广告的方法,该方法接收一个BUNativeAd对象。 2. 在这个方法中,首先将之前注册的广告视图取消注册(如果有的话),然后重新注册新的广告视图。 3. 在cell的`prepareForReuse`方法中,同样需要取消广告视图的注册,并清空广告视图上的数据。 具体代码实现: 自定义UITableViewCell(假设类名为AdTableViewCell): ```objective-c @interface AdTableViewCell : UITableViewCell @property (nonatomic, strong) UIView *adContainerView; // 广告容器视图,包含可点击的视图(比如ViewA) @property (nonatomic, strong) BUNativeAd *nativeAd; // 当前cell展示的广告 @end @implementation AdTableViewCell - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { [self setupViews]; } return self; } - (void)setupViews { // 创建广告容器视图,并添加到contentView上(根据引用[1]和[3]) self.adContainerView = [[UIView alloc] init]; [self.contentView addSubview:self.adContainerView]; // 设置adContainerView的约束 // ... 省略布局代码 // 在adContainerView上添加其他子视图(比如ViewA) // 注意:ViewA应该是adContainerView的子视图,并且需要被注册为可点击视图 } - (void)configWithNativeAd:(BUNativeAd *)nativeAd { // 1. 先取消之前广告的注册(如果有) if (self.nativeAd) { [self.nativeAd unregisterView]; } // 2. 保存新的广告 self.nativeAd = nativeAd; // 3. 渲染广告视图(根据广告数据更新adContainerView中的子视图内容) // 4. 注册广告容器和可点击视图 // 注意:可点击视图应该是adContainerView的子视图,这里假设有一个按钮ViewA(实际可能是多个视图) UIView *viewA = ...; // 从adContainerView中获取或创建 [nativeAd registerContainer:self.adContainerView withClickableViews:@[viewA]]; // 5. 设置广告的代理(如果需要处理广告事件) nativeAd.delegate = self; } - (void)prepareForReuse { [super prepareForReuse]; // 在复用前取消广告的注册 if (self.nativeAd) { [self.nativeAd unregisterView]; self.nativeAd.delegate = nil; self.nativeAd = nil; } // 同时,清空广告容器视图中的内容(或者重置为默认状态) // ... 根据实际情况清空 } @end ``` 在tableView的代理方法中: ```objective-c - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { AdTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AdCell" forIndexPath:indexPath]; // 获取对应位置的广告数据 BUNativeAd *nativeAd = self.ads[indexPath.row]; [cell configWithNativeAd:nativeAd]; return cell; } ``` 注意事项: 1. 在`configWithNativeAd:`方法中,一定要先取消之前广告的注册(如果存在),然后再注册新的广告。 2. 在`prepareForReuse`方法中,同样要取消广告的注册,并将广告的代理置为nil,避免旧广告的事件回调到已经被复用的cell上。 3. 广告的容器视图(adContainerView)必须是cell.contentView的子视图,并且可点击视图(如ViewA)必须是容器视图的子视图。 这样处理可以确保当cell被复用时,之前的广告会被正确取消注册,从而避免复用后仍响应广告点击。 另外,根据引用[4],如果我们需要订阅cell内部的按钮事件(比如广告的点击),也可以使用RxSwift等响应式框架,但同样需要注意复用问题。不过,由于广告SDK本身提供了注册和取消注册的方法,我们按照上述方式处理即可。 如果还有问题,可能需要检查广告SDK的文档,确认`unregisterView`方法是否被正确调用,以及广告视图的注册是否要求唯一性等。 希望以上解决方案对您有帮助。</think>在 UITableViewCell 中正确处理 BUNativeAd 的点击事件并避免复用问题,需要遵循以下关键步骤: ### 解决方案 1. **广告注册与解注册** ```objective-c // 自定义 UITableViewCell @interface AdTableViewCell : UITableViewCell @property (nonatomic, strong) BUNativeAd *nativeAd; @end @implementation AdTableViewCell - (void)configWithAd:(BUNativeAd *)ad { // 先解注册旧广告 if (_nativeAd) { [_nativeAd unregisterView]; // 关键:解除旧绑定 } _nativeAd = ad; // 清除旧视图内容 [self.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; // 创建广告容器视图(必须添加到contentView) UIView *adContainer = [[UIView alloc] initWithFrame:self.contentView.bounds]; [self.contentView addSubview:adContainer]; // 注册广告视图(示例) [ad registerContainer:adContainer withClickableViews:@[adContainer] // 指定可点击区域 ]; } - (void)prepareForReuse { [super prepareForReuse]; [self.nativeAd unregisterView]; // 关键:复用前解注册 self.nativeAd = nil; } @end ``` 2. **在 CellForRow 中正确配置** ```objective-c - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { AdTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; BUNativeAd *ad = self.ads[indexPath.row]; // 每次复用都重新配置 [cell configWithAd:ad]; return cell; } ``` ### 关键注意事项 1. **必须使用 contentView** - 所有自定义视图(包括广告容器)必须添加到 `cell.contentView` 而非直接添加到 cell(引用[1][^1], 引用[3][^3]) ```objective-c // 正确做法 [self.contentView addSubview:adContainer]; // 错误做法(会导致布局问题) [self addSubview:adContainer]; ``` 2. **复用处理三原则** - `prepareForReuse` 中必须调用 `unregisterView` - 配置新广告前必须先解注册旧广告 - 清除旧广告视图内容(防止视图残留) 3. **点击事件处理** - 使用 `registerContainer:withClickableViews:` 明确指定可点击视图 - 避免将整个 cell 设为可点击,只指定广告区域内的特定视图 4. **内存管理** ```objective-c - (void)dealloc { [_nativeAd unregisterView]; // 防止内存泄漏 } ``` ### 典型错误场景分析 **问题:** 滑动列表后旧广告仍响应点击 **原因:** 未在 `prepareForReuse` 中调用 `unregisterView`,导致 cell 复用后广告绑定未解除 **问题:** 多个广告同时响应事件 **原因:** 未在配置新广告前调用 `unregisterView`,导致新旧广告叠加绑定 ### 优化建议 1. 使用单独的广告容器视图,便于管理生命周期 2. 实现广告状态标记: ```objective-c // 在 cell 中增加状态标记 @property (nonatomic, assign) BOOL adRegistered; // 配置时标记 adRegistered = YES; // 解注册时清除标记 - (void)unregisterAdIfNeeded { if (_adRegistered) { [_nativeAd unregisterView]; _adRegistered = NO; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值