我是Cocoa的新手,我試圖通過掃描我們的DHCP服務器日誌查詢以太網硬件地址並注意最近的事務來創建一個應用程序來審計我們的網絡設備。我創建了一個基於文檔的程序,它將執行該操作,並在綁定到數組控制器的tableView中顯示其結果(可變字典的可變數組)。如何重新加載鏈接到數組控制器的tableview?
我現在想要讀取從網絡IPAM管理器導出的文件,該文件由分配給我們的虛擬LAN的以太網硬件地址列表組成,並將它與原始數組進行比較,並在缺少適當註釋的設備中添加。我已經通過文檔上的按鈕(readSecondFile)觸發了一個操作。還有添加和刪除按鈕用於手動輸入,或者更有用的是,從列表中刪除設備。還有一個用於導出編輯數組的保存例程。
這一切都正常工作,只有一個例外。當讀入第二個文件時,tableView將不會重新繪製,重新加載其數據或其他內容,直到您單擊列標題來排序或添加:或使用ArrayController方法刪除:。發生這種情況時,附加條目將出現在tableView中。
我的問題是如何讓tableView重新繪製readSecondFile例程末尾的擴展數組?我已經使用了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;
[email protected]"";
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
你曾經實例化過一個dataArrayController嗎?也許在筆尖? (你把它綁定到MyDocument.lines?) – paulmelnikow
我在nib中添加了一個arrayController對象,是的。 我認爲問題出在我向數組添加'macs'的方法,因爲隨後的測試顯示readSecondFile的第一次運行將添加到數組,並且tableView在重新排序時跟上它,但隨後的運行'readSecondFile'更新數組,但更改從未反映在tableView中。 – TRT
我在'MyDocument.m'中註釋了'import'dateArrayController.h'',並在'MyDocument.h'文件中添加了一個'IBOutlet NSArrayController * dataArrayController;'。 arrayController現在響應'setContent:'方法並按預期更新tableView。感謝您的幫助,但是如果您有任何其他指標願意分享,我會很感激,因爲我非常喜歡可可! – TRT