Objective-C跨类向NSMutableArray添加对象及重复符号问题求助
解决Objective-C重复符号错误、跨类数组操作及循环赋值异常问题
问题背景
我刚接触Objective-C和Swift,现在遇到了几个棘手的问题:
- 我在
ExampleMenuViewController.m和SomeClass.m里都声明了NSMutableArray *vcTabs;,Xcode直接报错重复符号“_vcTabs” - 我需要从
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
相关产品推荐
相关产品推荐

