You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Objective-C跨类向NSMutableArray添加对象及重复符号问题求助

解决Objective-C重复符号错误、跨类数组操作及循环赋值异常问题

问题背景

我刚接触Objective-C和Swift,现在遇到了几个棘手的问题:

  1. 我在ExampleMenuViewController.m和SomeClass.m里都声明了NSMutableArray *vcTabs;,Xcode直接报错重复符号“_vcTabs”
  2. 我需要从SomeClass.m往ExampleMenuViewController里已经初始化好的vcTabs数组加对象,但现在处理additional_tabs(里面有17个元素)后,最终只得到一个带最后一个对象属性的标签。

附上我的代码片段:

SomeClass.m中的相关代码

if ([Tools isNonullValueForKey:[dictionary valueForKey:@"additional_tabs"]]) {
    additional_tabs = [dictionary valueForKey:@"additional_tabs"];
    NSLog(@"additionalTabs count: %lu", [additional_tabs count]);
    for (int i = 0; i < [additional_tabs count]; i++) {
        if ([Tools isNonullValueForKey:[additional_tabs valueForKey:@"_id"]]) {
            additional_tab_id = [[additional_tabs valueForKey:@"_id"] objectAtIndex:i];
        }
        if ([Tools isNonullValueForKey:[additional_tabs valueForKey:@"names"]]) {
            NSDictionary *dic = [[additional_tabs valueForKey:@"names"] objectAtIndex:i];
            _en_additional_tab_name = [dic valueForKey:@"en"];
            _pl_additional_tab_name = [dic valueForKey:@"pl"];
        }
        if ([Tools isNonullValueForKey:[additional_tabs valueForKey:@"url"]]) {
            additional_tab_url = [[additional_tabs valueForKey:@"url"] objectAtIndex:i];
            //NSLog(@"additional_tab_url: %@", _additional_tab_url);
        }
        [vcTabs addObject:[[VCTab alloc] initWithIdAndTypeAndUrl:additional_tab_id :VCTabAdditional :additional_tab_url]];
        NSLog(@"%@ %d %@ %@ %@ %@", @"pos", i, @"id: ", additional_tab_id, @"url: ", additional_tab_url);
    }
}

ExampleMenuViewController的initVCTabs方法

- (void)initVCTabs {
    vcTabs = [[NSMutableArray alloc] init];
    [vcTabs removeAllObjects];
    if ([Tools getBooleanUserDefault:@"example_visible_tab_attendees" :YES]) {
        [vcTabs addObject:[[VCTab alloc] initWithType:VCTabAttendees]];
    }
    (...)
    if ([Tools getBooleanUserDefault:@"example_visible_tab_user_info" :YES]) {
        [vcTabs addObject:[[VCTab alloc] initWithType:VCTabUserInfo]];
    }
    if ([Tools getStringUserDefault:@"example_additional_tab_id" :@""]) {
        NSString *additionalTabId = [Tools getStringUserDefault:@"conference_additional_tab_id" :@""];
        NSString *additionalTabUrl = [Tools getStringUserDefault:@"conference_additional_tab_url" :@""];
        NSLog(@"additionalTabId %@", additionalTabId);
        NSLog(@"additionalTabUrl %@", additionalTabUrl);
        [vcTabs addObject:[[VCTab alloc] initWithIdAndTypeAndUrl:additionalTabId :VCTabAdditional :additionalTabUrl]];
    }
}

解决方案

1. 先搞定重复符号错误

你现在的问题是把vcTabs当成全局变量在两个文件里都声明了,链接器会认为这是两个相同的符号,所以报错。正确的做法是把vcTabs改成ExampleMenuViewController的实例属性:

  • 在ExampleMenuViewController.h里添加属性声明:
@property (nonatomic, strong) NSMutableArray *vcTabs;
  • 然后在initVCTabs方法里初始化时用self.vcTabs:
- (void)initVCTabs {
    self.vcTabs = [[NSMutableArray alloc] init];
    // 原来的初始化逻辑不变,只是把所有vcTabs改成self.vcTabs
    [self.vcTabs removeAllObjects];
    if ([Tools getBooleanUserDefault:@"example_visible_tab_attendees" :YES]) {
        [self.vcTabs addObject:[[VCTab alloc] initWithType:VCTabAttendees]];
    }
    // ... 其他代码同理
}

这样vcTabs就属于ExampleMenuViewController的实例,不会有全局重复的问题了。

2. 从SomeClass访问ExampleMenuViewController的vcTabs

要在SomeClass里操作另一个类的实例数组,核心是拿到ExampleMenuViewController的实例,这里给你几种常用方案:

  • 方案一:通过导航栈获取实例(如果你的菜单VC在导航栈中)
// 在SomeClass.m里
ExampleMenuViewController *menuVC = nil;
for (UIViewController *vc in self.navigationController.viewControllers) {
    if ([vc isKindOfClass:[ExampleMenuViewController class]]) {
        menuVC = (ExampleMenuViewController *)vc;
        break;
    }
}
if (menuVC) {
    // 这里就可以用menuVC.vcTabs来操作数组了
}
  • 方案二:直接传递实例引用(简单直接,适合关联紧密的类)
    给SomeClass加一个弱引用属性:
// SomeClass.h
@property (nonatomic, weak) ExampleMenuViewController *menuVC;

然后在创建SomeClass对象的时候,把菜单VC的实例传进去:

// 在ExampleMenuViewController里创建SomeClass的地方
SomeClass *someInstance = [[SomeClass alloc] init];
someInstance.menuVC = self;

之后在SomeClass.m里就可以通过self.menuVC.vcTabs来添加对象了。

  • 方案三:代理模式(更解耦,适合复杂场景)
    定义一个代理协议,让ExampleMenuViewController遵守,SomeClass通过代理回调把要添加的VCTab对象传递过去,这种方式代码结构更清晰,适合后期维护。

3. 修复循环后只显示最后一个对象的问题

你这个问题的核心是循环中复用了全局/实例变量,导致每次循环都覆盖了之前的值,最后所有VCTab对象都引用了同一个变量的最后一次赋值。修复方法很简单:

  • 在循环内部声明局部变量,每次循环都用新的变量存储当前项的数据;
  • 直接取当前索引的字典,不要用valueForKey遍历整个数组(这种方式效率低还容易出错)。

修改后的代码如下:

if ([Tools isNonullValueForKey:dictionary[@"additional_tabs"]]) {
    NSArray *additionalTabs = dictionary[@"additional_tabs"];
    NSLog(@"additionalTabs count: %lu", (unsigned long)additionalTabs.count);
    
    for (int i = 0; i < additionalTabs.count; i++) {
        // 每次循环都声明局部变量,避免覆盖
        NSString *tabId = nil;
        NSString *enTabName = nil;
        NSString *plTabName = nil;
        NSString *tabUrl = nil;
        
        // 直接取当前索引的字典,这才是正确的遍历方式
        NSDictionary *currentTabDict = additionalTabs[i];
        
        if ([Tools isNonullValueForKey:currentTabDict[@"_id"]]) {
            tabId = currentTabDict[@"_id"];
        }
        if ([Tools isNonullValueForKey:currentTabDict[@"names"]]) {
            NSDictionary *nameDict = currentTabDict[@"names"];
            enTabName = nameDict[@"en"];
            plTabName = nameDict[@"pl"];
        }
        if ([Tools isNonullValueForKey:currentTabDict[@"url"]]) {
            tabUrl = currentTabDict[@"url"];
        }
        
        // 创建新的VCTab对象并添加到目标数组
        VCTab *newTab = [[VCTab alloc] initWithIdAndTypeAndUrl:tabId :VCTabAdditional :tabUrl];
        [self.menuVC.vcTabs addObject:newTab]; // 这里用之前拿到的menuVC实例
        NSLog(@"pos %d id: %@ url: %@", i, tabId, tabUrl);
    }
}

另外还要检查你的VCTab初始化方法,确保它把传入的tabId、tabUrl等参数正确赋值为自己的实例变量,而不是引用外部变量,这也是可能导致所有对象显示同一内容的原因。


内容的提问来源于stack exchange,提问作者handzel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 00:17:38