我的WindowController对于一个应用程序来说有一个问题,该应用程序基本上是一个项目列表,位于可以从菜单栏打开的面板上。
要打开面板,用户必须单击菜单栏中的应用程序状态项。该应用程序加载正常,如果面板从一开始就打开(并且您不点击状态项),一切正常。但是,如果它在启动时隐藏并且单击了statusitem以打开面板,则应用程序开始吃掉大量的RAM,而不会从创建此效果的循环中消失。
我使用了一些断点来尝试找到问题。似乎我的Window Controller中的一些方法不断相互调用,创建了一个无限循环。但我无法弄清楚原因。 也许你们其中一个人可以发现问题。如果有任何其他代码行感兴趣,我会尝试将它们发送给您。但是,目前这是应用程序的核心。其余的不包含那么多逻辑(除了AppDelegate)。
这是控制器的.m文件:
//
// UIController.m
// hourglass
//
// Created by Matze on 24/04/14.
// Copyright (c) 2014 hourglass. All rights reserved.
//
#import "UIController.h"
@implementation UIController
- (id)initWithDelegate:(id<UIControllerDelegate>)delegate {
self = [super initWithWindowNibName:@"UI"];
if (self != nil) {
_delegate = delegate;
}
return self;
}
- (void)deleteSelectedObjects {
NSArray *objectArray = [_Tasks selectedObjects];
for (int i = 0; i < [objectArray count]; i++) {
NSManagedObject *mo2delete = [objectArray objectAtIndex:i];
[[[NSApp delegate] managedObjectContext] deleteObject: mo2delete];
}
}
#pragma Actions
- (IBAction)buttonDelete:(id)sender {
NSUInteger row = [TableView rowForView:sender];
[TableView selectRowIndexes:[[NSIndexSet alloc] initWithIndex:row] byExtendingSelection:NO];
[self deleteSelectedObjects];
}
- (void)keyDown:(NSEvent *)event {
unichar key = [[event charactersIgnoringModifiers] characterAtIndex:0];
if(key == NSDeleteCharacter)
{
if([TableView selectedRow] == -1)
{
NSBeep();
}
BOOL isEditing = [[NSApp delegate]isEditing];
if (!isEditing)
{
[self deleteSelectedObjects];
return;
}
}
[super keyDown:event];
}
#pragma UI Drawing & Animation
- (void)awakeFromNib
{
[super awakeFromNib];
// Create Panel
NSPanel *panel = (id)[self window];
[panel setAcceptsMouseMovedEvents:YES];
[panel setLevel:NSPopUpMenuWindowLevel];
[panel setOpaque:NO];
[panel setBackgroundColor:[NSColor clearColor]];
// Resize Panel
NSRect panelRect = [[self window] frame];
panelRect.size.height = POPUP_HEIGHT;
[[self window] setFrame:panelRect display:NO];
}
- (NSRect)statusRectForWindow:(NSWindow *)window {
NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect statusRect = NSZeroRect;
statusItemView = nil;
if ([[self delegate] respondsToSelector:@selector(statusItemViewForUIController:)]) {
statusItemView = [[self delegate] statusItemViewForUIController:self];
}
if (statusItemView) {
statusRect = [statusItemView globalRect];
statusRect.origin.y = NSMinY(statusRect) - NSHeight(statusRect) - 2 ;
} else {
statusRect.size = NSMakeSize(STATUS_ITEM_VIEW_WIDTH, [[NSStatusBar systemStatusBar] thickness]);
statusRect.origin.x = roundf((NSWidth(screenRect) - NSWidth(statusRect)) / 2);
statusRect.origin.y = NSHeight(screenRect) - NSHeight(statusRect) * 2;
}
return statusRect;
}
- (void)setHasActivePanel:(BOOL)flag
{
if (_hasActivePanel != flag)
{
_hasActivePanel = flag;
if (_hasActivePanel)
{
[self openPanel];
}
else
{
[self closePanel];
}
}
}
- (void)windowWillClose:(NSNotification *)notification {
[self setHasActivePanel:NO];
}
- (void)windowDidResignKey:(NSNotification *)notification {
if ([[self window] isVisible]) {
[self setHasActivePanel:NO];
}
}
- (void)windowDidResize:(NSNotification *)notification {
NSWindow *panel = [self window];
NSRect statusRect = [self statusRectForWindow:panel];
NSRect panelRect = [panel frame];
CGFloat statusX = roundf(NSMidX(statusRect));
CGFloat panelX = statusX - NSMinX(panelRect);
CGFloat maxX = NSMaxX([[self backgroundView] bounds]);
CGFloat maxY = NSMaxY([[self backgroundView] bounds]);
self.backgroundView.triangle = panelX; // @Jan: why is a setter method not possible (i.e. setTriangle)
NSRect buttonRect = [[self buttonadd] frame];
buttonRect.size.width = BUTTON_SIZE;
buttonRect.size.height = buttonRect.size.width;
buttonRect.origin.x = maxX - buttonRect.size.width;// * 1.5;
buttonRect.origin.y = maxY - TRIANGLE_HEIGHT - buttonRect.size.height;// * 1.5;
[[self buttonadd] setFrame:buttonRect];
// NSRect listButtonRect = NSMakeRect(NSMinX([[self backgroundView] bounds]), buttonRect.origin.y, buttonRect.size.width, buttonRect.size.height) ;
// [[self buttonlist] setFrame:listButtonRect];
NSRect tableRect = [[self tableScrollView] frame];
tableRect.size.width = maxX;
tableRect.size.height = maxY - TRIANGLE_HEIGHT - buttonRect.size.height;
tableRect.origin.x = self.backgroundView.frame.origin.x;
tableRect.origin.y = maxY - POPUP_HEIGHT;
[[self tableScrollView] setFrame:tableRect];
}
- (void)cancelOperation:(id)sender {
[self setHasActivePanel:NO];
}
- (void)openPanel {
NSWindow *panel = [self window];
NSRect screenRect = [[[NSScreen screens] objectAtIndex:0] frame];
NSRect statusRect = [self statusRectForWindow:panel];
NSRect panelRect = [panel frame];
panelRect.size.width = PANEL_WIDTH;
panelRect.origin.x = roundf(NSMidX(statusRect) - NSWidth(panelRect) / 2);
panelRect.origin.y = NSMaxY(statusRect) - NSHeight(panelRect);
[panel setAlphaValue:0];
[panel setFrame:statusRect display:YES];
[panel makeKeyAndOrderFront:nil];
NSTimeInterval openDuration = OPEN_DURATION;
// For testing
NSEvent *currentEvent = [NSApp currentEvent];
if ([currentEvent type] == NSLeftMouseDown) {
NSUInteger clearFlags = ([currentEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); // @Jan
BOOL shiftPressed = (clearFlags == NSShiftKeyMask);
BOOL shiftOptionPressed = (clearFlags == (NSShiftKeyMask | NSAlternateKeyMask));
if (shiftPressed || shiftOptionPressed) {
openDuration *= 10;
if (shiftOptionPressed)
NSLog(@"Icon is at %@\n\tMenu is on screen %@\n\tWill be animated to %@",
NSStringFromRect(statusRect), NSStringFromRect(screenRect), NSStringFromRect(panelRect));
}
}
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:openDuration];
[[panel animator] setFrame:panelRect display:YES];
[[panel animator] setAlphaValue:1];
[NSAnimationContext endGrouping];
}
- (void)closePanel {
[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:CLOSE_DURATION];
[[[self window] animator] setAlphaValue:0];
[NSAnimationContext endGrouping];
dispatch_after(dispatch_walltime(NULL, NSEC_PER_SEC * CLOSE_DURATION * 2), dispatch_get_main_queue(), ^{
[[self window] orderOut:nil];
});
}
- (NSColor*)colorForIndex:(NSInteger)index {
NSManagedObjectContext *context = [[NSApp delegate] managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Task"
inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSError *error;
NSInteger itemCount = [context countForFetchRequest:fetchRequest error:&error];
float val = 0;
float brightness = 0.63;
if( itemCount < 11 )
{
val = brightness + ((0.1/10)*(index*3));
}
else
{
val = brightness + ((0.1/itemCount)*(index*(3)));
}
return [NSColor colorWithDeviceHue: 0.57
saturation: 0.67
brightness: val
alpha: 1
];
}
- (void)tableView:(NSTableView *)tableView
didAddRowView:(NSTableRowView *)rowView
forRow:(NSInteger)row {
rowView.backgroundColor = [self colorForIndex:row];
}
- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
[statusItemView setStatusContent:[object valueForKeyPath:keyPath]];
}
@end
这里是.h文件:
//
// UIController.h
// hourglass
//
// Created by Matze on 24/04/14.
// Copyright (c) 2014 hourglass. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import "GlobalProperties.h"
#import "StatusItemView.h"
#import "BackgroundView.h"
#import "RFOverlayScrollView.h"
@class UIController;
@protocol UIControllerDelegate <NSObject>
@optional
- (StatusItemView *)statusItemViewForUIController:(UIController *)controller;
@end
@interface UIController : NSWindowController <NSWindowDelegate> {
IBOutlet NSTableView *TableView;
StatusItemView *statusItemView;
}
//TODO: Split Controller function for views into separate Controller Classes (i.e. BackgroundViewController)
@property (nonatomic, unsafe_unretained) IBOutlet BackgroundView *backgroundView;
@property (nonatomic, unsafe_unretained) IBOutlet RFOverlayScrollView *tableScrollView;
@property (strong) IBOutlet NSButton *buttonadd;
@property (strong) IBOutlet NSArrayController *Tasks;
@property (nonatomic) BOOL hasActivePanel;
@property (nonatomic, unsafe_unretained, readonly) id<UIControllerDelegate> delegate;
- (id) initWithDelegate:(id<UIControllerDelegate>)delegate;
- (void)openPanel;
- (void)closePanel;
- (void)deleteSelectedObjects;
- (NSColor*)colorForIndex:(NSInteger)index;
- (IBAction)buttonDelete:(id)sender;
@end
非常感谢任何帮助!