Cocoa 如何重新加载链接到阵列控制器的tableview?

Cocoa 如何重新加载链接到阵列控制器的tableview?,cocoa,nstableview,nsarraycontroller,Cocoa,Nstableview,Nsarraycontroller,我是Cocoa的新手,我正在尝试创建一个应用程序,通过扫描DHCP服务器日志中的以太网硬件地址并记录最近的事务来审计我们的网络设备。我已经创建了一个基于文档的程序来实现这一点,它在绑定到数组控制器的tableView中显示其结果(可变字典的可变数组) 现在,我想读取从network IPAM manager导出的一个文件,该文件包含分配给虚拟LAN的以太网硬件地址列表,并将其与原始阵列进行比较,添加缺少适当注释的设备。我通过文档(readSecondFile)上的一个按钮触发的操作完成了此操作。

我是Cocoa的新手,我正在尝试创建一个应用程序,通过扫描DHCP服务器日志中的以太网硬件地址并记录最近的事务来审计我们的网络设备。我已经创建了一个基于文档的程序来实现这一点,它在绑定到数组控制器的tableView中显示其结果(可变字典的可变数组)

现在,我想读取从network IPAM manager导出的一个文件,该文件包含分配给虚拟LAN的以太网硬件地址列表,并将其与原始阵列进行比较,添加缺少适当注释的设备。我通过文档(readSecondFile)上的一个按钮触发的操作完成了此操作。还有添加和删除按钮,用于手动输入,或者更有用的是,用于从列表中删除设备。还有一个用于导出已编辑数组的保存例程

除了一个例外,一切正常。读入第二个文件时,tableView将不会重新绘制、重新加载其数据或其他内容,直到您使用ArrayController方法单击列标题进行排序或添加:或删除:为止。发生这种情况时,其他条目将显示在tableView中

我的问题是如何在readSecondFile例程结束时使用扩展的数组重新绘制tableView?我已经尝试过KeyValueObserving,但我不确定这是否是必需的,尽管它会起作用(如果我能让它起作用的话!我已经要求ArrayController观察阵列并通知阵列的更改,但我不确定是否需要做更多

有人能帮忙吗?非常感谢

[附加]刚刚注意到,它确实会重新绘制,因为它为阵列中的现有设备添加了一些注释,但它不会显示具有IPAM条目但没有DHCP活动的附加设备

[附加-请求代码]

//MyDocument.h
#import <Cocoa/Cocoa.h>
#import <stdio.h>
#import <regex.h>
#import <AppKit/AppKit.h>

typedef enum _dataFormat {
    Unknown = 0,
    PlainText = 1,
    RichText = 2,
    RTFD = 3,
} DataFormat;

int count, b, i, q, p;


@interface MyDocument : NSDocument
{
    NSMutableArray *macs;
    NSMutableDictionary *machines;
    NSArray *filteredLines;
    NSArray *lines;
    IBOutlet NSTextField *processing;
    IBOutlet NSProgressIndicator *myProgress;
    IBOutlet NSButton *removeButton;
    IBOutlet NSButton *readSecondFile;
    IBOutlet NSTableView *tableView;
    NSString *fileString;
}

-(IBAction)readSecondFileFromURL:(id)sender;

-(NSMutableArray *)macs;
-(NSMutableDictionary *)machines;
-(void)setMacs:(NSArray *)newMacs;
-(void)setMachines:(NSMutableDictionary *)newMachines;
-(NSArray *)filteredLines;
-(NSArray *)lines;


@end


//  MyDocument.m

#import "MyDocument.h"
#import "dataArrayController.h"

@implementation MyDocument

- (id)init
{
    self = [super init];
    if (self) {
        [self setMacs:[NSMutableArray array]];    
    }
    //[dataArrayController bind:@"macs" // see update
    //             toObject:self
    //          withKeyPath:@"mac"
    //              options:0];

    // set up an observer for arrangedObjects
    [dataArrayController addObserver:self
                      forKeyPath:@"mac"
                         options:0
                         context:nil];

    return self;
}

-(void)dealloc
{
    [self setMacs:nil];
    [super dealloc];
}

-(NSArray *)macs
{
    return macs;
}

-(NSArray *)filteredLines
{
    return filteredLines;
}

-(NSArray *)lines
{
    return lines;
}

-(NSMutableDictionary *)machines
{
    return machines;
}

-(void)setMacs:(NSMutableArray *)newMacs
{
    [newMacs retain];
    [macs release];
    macs=newMacs;
    //[macs setArray:newMacs];
}

-(void)setMachines:(NSMutableDictionary *)newMachines
{
    [newMachines retain];
    [machines release];
    machines = newMachines;
    [newMachines release];
}

-(void)setLines:(NSArray *)newLines
{
    [newLines retain];
    [filteredLines release];
    filteredLines = newLines;
}

- (NSString *)windowNibName
{
      return @"MyDocument";
}

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    [tableView reloadData];
}

-(BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError //Write a text file of the array (macs) contents 
{
    NSMutableString *csvString = [NSMutableString string];
    NSEnumerator *macEnum = [macs objectEnumerator];
    id data;
    while (data = [macEnum nextObject] ){
        NSNumber *mac = [data valueForKey:@"mac"];
        NSNumber *ack = [data valueForKey:@"ack"];
        NSString *vLan = [data valueForKey:@"vLan"];
        [csvString appendString:[NSString stringWithFormat:@"%@,%@,%@\n", mac, ack, vLan]];
    }
    return [csvString writeToURL:absoluteURL atomically:NO encoding:NSUTF8StringEncoding error:outError];
}

-(BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError //Check the log file existance
{
    fileString = [NSString stringWithContentsOfURL:absoluteURL encoding:NSUTF8StringEncoding error:outError];
    if (nil == fileString) return NO;
    return YES;
}

-(BOOL)readSecondFileFromURL:(id)sender //error:(NSError **)outError//(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
{
    double progress;
    NSString* string = @"00:00:00:00:00:00";
    NSString* pattern = @"[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}";
    NSString* result = nil;
    NSString* listItem = nil;   
    NSString* mac = nil;
    NSArray* extracted = nil;
    NSMutableDictionary* obj=nil;
    NSDate *date = NULL;
    NSOpenPanel* openDlg = [NSOpenPanel openPanel];
    [openDlg setCanChooseFiles:YES];
    [openDlg setCanChooseDirectories:YES];

    if ( [openDlg runModalForDirectory:nil file:nil] == NSOKButton )
     {
        NSArray* files = [openDlg filenames];
//NSLog(@"%@",[files description]);
        // Loop through all the files and process them.
        for( b = 0; b < [files count]; b++ )
         {
            extracted = [macs valueForKey:@"mac"];
//NSLog(@"%@", [extracted description]);
            NSString* fileLoc = [files objectAtIndex:b];
//NSLog(@"%@",fileLoc);
            fileString = [NSString stringWithContentsOfFile:fileLoc encoding:NSUTF8StringEncoding error:nil]; 
            if (fileString == nil) return NO;

            lines = [fileString componentsSeparatedByString:@"\n"]; // each line, adjust character for line endings
            [processing setStringValue:@"Processing..."];
            [processing display];

            filteredLines = lines; //[lines filteredArrayUsingPredicate:pred];
            count = [filteredLines count];
//NSLog(@"%d",count);
//NSLog(@"%@",[filteredLines description]);

            [myProgress setDoubleValue:0.5];
            [myProgress setIndeterminate:NO];
            [myProgress displayIfNeeded];

            i=0;
            listItem  = [[NSString alloc] initWithString: @""];

            for (NSString *ent in filteredLines) {
                string=ent;
                result=NULL;
                listItem=@"";
                i++;
                progress = 100*((double)i/(double)count);
                q = progress;
//NSLog(@"%d",i);
                if (q > p) {
                    [myProgress setDoubleValue:progress];
                    [myProgress displayIfNeeded];
                    p = q;
                } //draw the progress bar 
//NSLog(@"%@",string);                          
                regex_t preg;           
//NSLog(@"B:%@",string);
                int err=regcomp(&preg,[pattern UTF8String],REG_EXTENDED);
                if(err) {
                    char errbuf[256];
                    regerror(err,&preg,errbuf,sizeof(errbuf));
                    [NSException raise:@"CSRegexException"
                                format:@"Could not compile regex %@: %s",pattern,errbuf];
                } //compile the regular expression
                //NSLog(@"C:%@",string);

                const char *cstr=[string UTF8String];
                regmatch_t match;
                if(regexec(&preg,cstr,1,&match,0)==0) {
                    result = [[[NSString alloc] initWithBytes:cstr+match.rm_so
                                                       length:match.rm_eo-match.rm_so encoding:NSUTF8StringEncoding] autorelease];
                    //NSLog(@"Result: %@",result);
                } //pull out the ethernet hardware address by scanning for the regex
//NSLog(@"D:%@",result);
                if(result != NULL){
                    if(result.length < 17) {
                    NSArray *listItems = [result componentsSeparatedByString:@":"];
                    for (NSString *bytepair in listItems){
                        //NSLog(@"split: %@", bytepair);
                        unsigned result;
                        if([[NSScanner scannerWithString: bytepair] scanHexInt: &result])
                            listItem=[listItem stringByAppendingFormat:@"%02x:", (int)result];
                        } //break address into array at colons
                    result=[listItem substringToIndex:17] ;
                    } //pad out to standard ethernet hardware address
                    mac = result;   
//NSLog(@"%@ %d",mac, [extracted containsObject:mac]);
                    if ([extracted containsObject:mac]){
                        for(id key in macs) {
                                if ([[key valueForKey:@"mac"] isEqualToString:[NSString stringWithFormat:@"%@", mac]]) {
                                   [key setValue:@"vLan OK" forKey:@"vLan"];    
                                } //Check if the mac is already registered and if so annotate it.
                         } //Annotate an existing entry
                    }   else {
                        date=[NSDate distantPast];
                        obj=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@",mac], @"mac", date, @"ack", @"No DHCP activity", @"vLan", nil];
                        NSIndexSet *loneIndex = [NSIndexSet indexSetWithIndex:[macs count]];
                        [dataArrayController willChange:NSKeyValueChangeInsertion valuesAtIndexes:loneIndex forKey:@"mac"];
                        [macs addObject:obj];
                        [dataArrayController didChange:NSKeyValueChangeInsertion valuesAtIndexes:loneIndex forKey:@"mac"];
                    }   //Add a new entry           
                }

            }

            //[myProgress setIndeterminate:YES];
            //[myProgress startAnimation:self];
            //[myProgress displayIfNeeded];
//NSLog(@"%@",[newMachines description]);
            //[self setMachines:newMachines];
//NSLog(@"%@",[machines description]);
            //mac = NULL;
            //for (mac in machines) {
            //  ack = [machines valueForKey:mac];
            //  NSLog(@"F:%@", mac);
                //[newMacs addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@",mac], @"mac", ack, @"ack", @"vLan", @"vLan", nil]];
            //} //Convert the machine dictionary into a format suitable for an array controller
            //[mac release];
            //[machines release];
            //[newMachines release];
            //[self setMacs:newMacs];
            //[dateFormat release];
            //[myProgress setDisplayedWhenStopped:NO];
            //[myProgress stopAnimation:self];
            //[myProgress setHidden:YES];
            //[processing setHidden:YES];
            //if ([macs count]>0){
            //  [removeButton setHidden:NO];
            //}
            [readSecondFile setHidden:NO];
            [readSecondFile display];
            //[extracted release];
                     }
     }

    [tableView reloadData];

    return YES;
}

- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{   [super windowControllerDidLoadNib:aController];
    [self showWindows];
    [removeButton setHidden:YES];
    [removeButton display];
    [readSecondFile setHidden:YES];
    [readSecondFile display];
    [processing setStringValue:@"Loading..."];
    [processing setHidden:NO];
    [processing display];
    [myProgress setHidden:NO];
    [myProgress setUsesThreadedAnimation:YES];
    [myProgress setIndeterminate:YES];
    [myProgress startAnimation:self];

    int count, i, q, p;
    double progress;

    NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF CONTAINS 'DHCP'"];  

    NSString* string = @"00:00:00:00:00:00";
    NSString* pattern = @"[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}";
    NSString* result = nil;
    NSString* listItem = nil;   
    NSString* mac = nil;
    NSString* ack = nil;    
    NSString* localeDetect = nil;
    NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];   // Convert string to date object
    NSDate *date = NULL;
    NSRange rangeForLocaleDetect = NSMakeRange (20, 3);
    NSMutableArray *newMacs = [NSMutableArray array];

    lines = [fileString componentsSeparatedByString:@"\n"]; // each line, adjust character for line endings
    [processing setStringValue:@"Processing..."];
    [processing display];

    filteredLines = [lines filteredArrayUsingPredicate:pred];
    count = [filteredLines count];

    NSMutableDictionary *newMachines = [NSMutableDictionary dictionaryWithCapacity:count];

    [myProgress setDoubleValue:0.5];
    [myProgress setIndeterminate:NO];
    [myProgress displayIfNeeded];

    i=0;
    p=0;

    for (NSString *ent in filteredLines) {
        string=ent;
        i++;
        progress = 100*((double)i/(double)count);
        q = progress;
        if (q > p) {
            [myProgress setDoubleValue:progress];
            [myProgress displayIfNeeded];
            p = q;
         } //draw the progress bar 

        listItem  = [[NSString alloc] initWithString: @""];
        localeDetect = [NSString stringWithFormat:@"%@",[string substringWithRange:rangeForLocaleDetect]];

        if ([localeDetect isEqualToString:@"UTC"]){
            [dateFormat setDateFormat:@"yyyy.MM.dd HH:mm:ss"];
            ack = [NSString stringWithFormat:@"%@", [string substringToIndex:19]];
        } else {
            [dateFormat setDateFormat:@"MMM dd HH:mm:ss"];
            ack = [NSString stringWithFormat:@"%@",[string substringToIndex:15]];

        }

        date = [dateFormat dateFromString:ack];
        regex_t preg;
        int err=regcomp(&preg,[pattern UTF8String],REG_EXTENDED);
        if(err) {
            char errbuf[256];
            regerror(err,&preg,errbuf,sizeof(errbuf));
            [NSException raise:@"CSRegexException"
                        format:@"Could not compile regex %@: %s",pattern,errbuf];
         } //compile the regular expression

        const char *cstr=[string UTF8String];
        regmatch_t match;
        if(regexec(&preg,cstr,1,&match,0)==0) {
            result = [[[NSString alloc] initWithBytes:cstr+match.rm_so
                                               length:match.rm_eo-match.rm_so encoding:NSUTF8StringEncoding] autorelease];
         } //pull out the ethernet hardware address by scanning for the regex

        if(result.length < 17) {
            NSArray *listItems = [result componentsSeparatedByString:@":"];
            for (NSString *bytepair in listItems){
                //NSLog(@"split: %@", bytepair);
                unsigned result;
                if([[NSScanner scannerWithString: bytepair] scanHexInt: &result])
                    listItem=[listItem stringByAppendingFormat:@"%02x:", (int)result];
             } //break address into array at colons
            result=[listItem substringToIndex:17] ;
        } //pad out to standard ethernet hardware address

        mac = result;
        NSDate *old = [newMachines valueForKey:mac];
            if (([date laterDate:old]==date) || old==NULL){
                [newMachines setValue:date forKey:mac];     
            } //Check for and compare dates for existing keys, as the log file might just be out of sequence
    } //For every line in the log which meets the Predicate, extract the relevant information.

    [myProgress setIndeterminate:YES];
    [myProgress startAnimation:self];
    [myProgress displayIfNeeded];

    [self setMachines:newMachines];

    for (mac in machines) {
        ack = [machines valueForKey:mac];
        [newMacs addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"%@",mac], @"mac", ack, @"ack", @"", @"vLan", nil]];
        } //Convert the machine dictionary into a format suitable for an array controller

    [self setMacs:newMacs];
    [dateFormat release];

    [myProgress setDisplayedWhenStopped:NO];
    [myProgress stopAnimation:self];
    [myProgress setHidden:YES];
    [processing setHidden:YES];
    if ([macs count]>0){
        [removeButton setHidden:NO];
    }
    [readSecondFile setHidden:NO];
    [readSecondFile display];


} //Process the file and display the relevant progress bars. Create and populate array.

- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
    // Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil.
    // You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
    // For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.

    if ( outError != NULL ) {
        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
    }
    return nil;
}

- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
    // Insert code here to read your document from the given data of the specified type.  If the given outError != NULL, ensure that you set *outError when returning NO.
    // You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead.     
    // For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead.

    if ( outError != NULL ) {
        *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
    }
    return YES;
}

@end
//MyDocument.h
#进口
#进口
#进口
#进口
typedef枚举数据格式{
未知=0,
纯文本=1,
RichText=2,
RTFD=3,
}数据格式;
整数计数,b,i,q,p;
@接口MyDocument:NSDocument
{
NSMUTABLEARRY*MAC;
NSMutableDictionary*机器;
NSArray*过滤线;
NSArray*线路;
ibnstextfield*处理;
IBN进度指示器*我的进度;
IBN按钮*移除按钮;
IBN按钮*readSecondFile;
ibnstableview*表视图;
NSString*fileString;
}
-(iAction)readSecondFileFromURL:(id)发件人;
-(NSMutableArray*)MAC;
-(NSMutableDictionary*)机器;
-(无效)SETMAC:(NSArray*)新MAC;
-(void)setMachines:(NSMutableDictionary*)newMachines;
-(NSArray*)过滤线;
-(NSArray*)线路;
@结束
//MyDocument.m
#导入“MyDocument.h”
#导入“dataArrayController.h”
@执行我的文件
-(id)init
{
self=[super init];
如果(自我){
[self-setMacs:[NSMutableArray]];
}
//[dataArrayController绑定:@“Mac”//请参阅更新
//对象:自我
//withKeyPath:@“mac”
//选项:0];
//为已安排的对象设置观察者
[dataArrayController添加观察者:self
分叉路径:@“mac”
选项:0
上下文:无];
回归自我;
}
-(无效)解除锁定
{
[self-setMacs:nil];
[super dealoc];
}
-(NSArray*)Mac
{
返回MAC;
}
-(NSArray*)过滤线
{
返回过滤线;
}
-(NSArray*)线路
{
回流线;
}
-(NSMutableDictionary*)机器
{
返回机器;
}
-(void)setMacs:(NSMutableArray*)newMacs
{
[新互委会保留];
[macs版本];
macs=newMacs;
//[macs setArray:newMacs];
}
-(void)setMachines:(NSMutableDictionary*)newMachines
{
[新机器保留];
[机器放行];
机器=新机器;
[新机器发布];
}
-(void)设置行:(NSArray*)换行
{
[保留换行符];
[过滤线释放];
filteredLines=换行符;
}
-(NSString*)windowNibName
{
返回@“MyDocument”;
}
-(void)observeValueForKeyPath:(NSString*)对象的键路径:(id)对象更改:(NSDictionary*)更改上下文:(void*)上下文
{
[tableView重新加载数据];
}
-(BOOL)writeToURL:(NSURL*)类型的绝对URL:(NSString*)类型名称错误:(NSError**)outError//编写数组(macs)内容的文本文件
{
NSMutableString*csvString=[NSMutableString];
N分子*macEnum=[macs objectEnumerator];
id数据;
而(数据=[macEnum nextObject]){
NSNumber*mac=[数据值forkey:@“mac”];
NSNumber*ack=[数据值forkey:@“ack”];
NSString*vLan=[data valueForKey:@“vLan”];
[csvString appendString:[NSString stringWithFormat:@“%@,%@,%@\n”,mac,ack,vLan]];
}
返回[csvString writeToURL:absoluteURL原子:无编码:NSUTF8StringEncoding错误:outError];
}
-(BOOL)readFromURL:(NSURL*)类型的绝对URL:(NSString*)类型名称错误:(NSError**)outError//检查日志文件是否存在
{
fileString=[NSString stringWithContentsOfURL:absoluteURL编码:NSUTF8StringEncoding错误:outError];
if(nil==fileString)返回NO;
返回YES;
}
-(BOOL)readSecondFileFromURL:(id)发送方//错误:(NSError**)outError/(NSURL*)类型的绝对URL:(NSString*)类型名错误:(NSError**)outError
{
双重进步;
NSString*string=@“00:00:00:00:00”;
NSString*模式=@“[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}”;
NSString*结果=nil;
NSString*listItem=nil;
NSString*mac=nil;
NSArray*提取=nil;
NSMutableDictionary*obj=nil;
NSDate*date=NULL;
NSOpenPanel*openDlg=[NSOpenPanel-openPanel];
[openDlg setCanChooseFiles:是];
[openDlg SetCanChoosedDirectories:是];
if([openDlg runModalForDirectory:nil file:nil]==NSOKButton)
{
NSArray*文件=[openDlg文件名];
//NSLog(@“%@,[文件说明]);
//L
[tableView reloadData];