Challenge: Make a Delegate


#1

I think I’ve got this working but there is a limitation.

I can set it up so it re-sizes the height OR width (and the other dimension changes appropriately) by changing the code. Is this the challenge? It might be nice to be able to re-size height and/or width with the same code. I think I could do it with a global NSSize variable to store the ‘old’ size. Checking width and height changes could allow re-sizing in both direction. Too much for now? Where would I declare a global NSSize variable? Thanks.

OK, I have it worked out. I added a variable to app.h in the interface section, initialized it in an init method in app.m. Checked for changes in width OR height in the delegate method and set the other dimension accordingly… interesting.

Delegates = action methods without buttons etc?


#2

The basic challenge is just to play with limiting resizing behavior. With Lion, resizing has gotten more complicated, as you found.

Sortof, but target/action is quite a bit simpler than delegates. Delegates are definitely about reacting to events in the application, just like action methods, but they can also be used to provide feedback (through a return value) to the class whose delegate you are, such as in this challenge, and the names of delegate methods are fixed.


#3

I came up to this solution

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { float actWidth = frameSize.width; float actHeight = frameSize.height; int newWidth; int newHeight; if ((actWidth / actHeight) > 2.0) { newWidth = actWidth; newHeight = actWidth / 2; } else if ((actWidth / actHeight) < 2.0) { newWidth = actHeight * 2; newHeight = actHeight; } NSSize mySize = NSMakeSize(newWidth, newHeight); return mySize; }

but I wonder if there might be a better solution by using setAspectRatio.


#4

I am new to Objective-C and am really stuck on this (Xcode 4.2.1 under Lion 10.7.2). I have tried it a couple of different ways, modeling the discussion in this Chapter, but then ended up trying the approach used by Adam in his solutions (downloaded from the Book’s website), but I still couldn’t get it to work. To that end, I made a Class delegate called MyClass; *.h and *.m code is below. I also listed the code for Ch6DelegateApp.h and Ch6DelegateApp.m files (see below) that were created with the Cocoa App. One problem seems to be that I am unable to connect the Window “Outlet”->delegate to MyClass.h (either programmatically or graphically, I can see this by right clicking on the Window Icon on the Xcode IB Dock). But I can see that the Window “Referencing Outlets” is connected to my Ch6Delegate.h file.

Files are below, please help! Thanks.

//  MyClass.h
// Intended as the app-delegate class
#import <Foundation/Foundation.h>
@interface MyClass : NSObject <NSWindowDelegate>
@end

I guess one key point is that conforming protocol is announced in the *.h file above (e.g., p. 101).
Then the corresponding m-file is:

[code]
// MyClass.m
// same code as Adam for the method:
#import “MyClass.h”
@implementation MyClass

  • (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
    {
    NSLog(@“resize”);
    NSSize newSize = frameSize;
    newSize.height = newSize.width * 2;
    return newSize;
    }
    @end [/code]
    The *.h and *.m files that were created with the Cocoa App are:
//  Ch6DelegateApp.h
#import <Cocoa/Cocoa.h>
@interface Ch6DelegateApp : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@end

and then the *.m file:

//  Ch6DelegateApp.m
#import "Ch6DelegateChallengeAppDelegate.h"
@implementation Ch6DelegateChallengeAppDelegate
@synthesize window = _window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    // Insert code here to initialize your application
}
@end

Thanks!!


#5

Ok, figured it out. I was correct in suspecting the problem was with connecting the Window “Outlet”->delegate to MyClass.h. All I had to do was drag an instance of the NSObject subclass (an Object) over to the IB Dock, then I was able to make the connection to the Window “Outlet”->delegate to the MyClass Object.
Thanks, good challenge,
–Bruce


#6

here’s my solution

any comment would be appreciated!

[code]- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
NSLog(@“qui sto ridimensionando!”);

// dimensioni correnti della finestra
NSSize currentSize = [sender frame].size;

// calcola la dimensione doppia di larghezza e altezza e le resituisce
NSSize doubleSize = NSMakeSize(currentSize.width, (currentSize.height * 2.0));
return doubleSize;

}
[/code]


#7

Ok, here is my one too :wink: The delegate of my window is AppDelegate.

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { return NSMakeSize(frameSize.width, frameSize.width*2); }


#8

thanks for sharing! :slight_smile:


#9

My answer was pretty much the same that others came to but I stuck two labels in the window so I could see the data changing as I resized.

AppDelegate.h

[code]#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *heightLabel;
@property (weak) IBOutlet NSTextField *widthLabel;

@end[/code]

AppDelegate.m

[code]#import “AppDelegate.h”

@implementation AppDelegate

@synthesize window = _window;
@synthesize heightLabel = _heightLabel;
@synthesize widthLabel = _widthLabel;

  • (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
    {

    [_heightLabel setFloatValue:(frameSize.width *2)];
    [_widthLabel setFloatValue:(frameSize.width)];

    return NSMakeSize(frameSize.width, (frameSize.width * 2));

}

@end[/code]


#10

Ahh.

Also if you aren’t worried about practicing with a delegate method, it’s much simpler to just set the aspect ratio for the window!

[code]#import “AppDelegate.h”

@implementation AppDelegate

@synthesize window = _window;
@synthesize heightLabel = _heightLabel;
@synthesize widthLabel = _widthLabel;

  • (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
    [_window setAspectRatio:NSMakeSize(1, 2)];
    }[/code]

And you are done.


#11

Using [NSWindow setAspectRatio:(NSSize)size] does require that the delegate have a reference to the window (shown as an IBOutlet property in the delegate class). Using windowWillResize: in a delegate does not require that reference since the NSWindow simply looks at the return value of the delegates implemented method and performs it’s own resizing.

Also, on my Lion machine at least, using the windowWillResize method does not allow the window to get smaller than the window decorations (zoom, minimize, etc. colored circles) would allow. setAspectRatio: allows the window to be resized to an unusably small size that hides the window decorations. I suppose you could set a minimum size to prevent that.

Performance using either method seemed equally smooth on my Macbook Air, but I suppose the setAspectRatio could be more efficient depending on how NSWindow implements it internally.


#12

Maybe I missed this topic in the book, but if you’re trying to make the connection between the window and its delegate by control-click-dragging in the xib editor, you might run into a problem that stumped me for a bit. I think it concerns nested objects.

When you click in the middle of the app’s window in the xib editor, you are selecting a view inside the window, not the window. Even if you select the window from the stack of objects–by control-clicking and selecting the window from the pop-up–you’ll not be able to drag from the middle of the window to the delegate object in the xib editor’s document outline. (That is, the bar with the objects in it.) As soon as you control-click in the window, you will see that the window-to-view selection change is indicated at the top of the Attributes Inspector on the right of the screen.

So how do you control-drag from the window itself? The trick is to drag from the title bar of the window. If you’ve indicated in the delegate object’s .h file that it conforms to the NSWindowDelegate protocol, you’ll get the black mini-window to pop up when you release the mouse on top of your delegate-to-be.

Same thing applies when you’re dragging to the Assistant editor window.

Also, (this is cool!) you can control-drag from one object to another in the xib editor’s document outline.


#13

Hello all,

I came up with the same code as Bruce, and Adam, but can’t seem to set my own (custom) class as a delegate of the window either programmatically or by control-dragging in IB (even if I drag an ‘Object’ out of the library, which then does not give me my class by the way). Any thoughts?
Marijn


#14

Can you say more about what you’ve tried, programmatically?

It should be pretty straightforward to set the delegate outlet in IB. Generally speaking your class should be one of the top level objects, such as in the case of the MainMenu.xib’s App Delegate, or, if you have done the NSWindowController chapter, the File’s Owner. Make sure you have the window selected and then control-click on it to bring up the connection panel. Drag from the circle for the ‘delegate’ item to the object you want to be the delegate. Are you trying something different, or is some part of this not working?

Adam


#15

Thank you for the quick reply Adam. I’ve managed to make the delegate connection now. The thing that had me confused was that my class did not appear in the IB dock. Dragging a NSObject out of the library did not help, until I finally remembered/realized that I should then select my class for the NSObject in the Identity Inspector…
Marijn

p.s.
really enjoying the book!


#16

My solution looks pretty much like the others submitted:

// Horizontal resize only NSSize mySize = NSMakeSize(frameSize.width, frameSize.width*2);

Then I started tinkering around with both directions (oldSize is an instance variable):

// horizontal and vertical resize NSSize mySize = NSMakeSize(frameSize.width, frameSize.height); if (mySize.height == oldSize.height) { // moving horizontally mySize.height = frameSize.width*2; oldSize.width = frameSize.width; oldSize.height = frameSize.height; } else { // moving vertically mySize.width = frameSize.height/2; oldSize.width = frameSize.width; oldSize.height = frameSize.height; }

Interesting to see some of the other takes on this here.


#17

[quote=“Vertex”]Ok, here is my one too :wink: The delegate of my window is AppDelegate.

- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize { return NSMakeSize(frameSize.width, frameSize.width*2); } [/quote]

My exact solution too :smiley:


#18

do the job !
But I delegate to get the result with NSLog.
After all this was the subject of the exercise… :slight_smile:

#import "NVAppDelegate.h"

@implementation NVAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    [_window setAspectRatio:NSMakeSize(2.0  ,1.0)] ;
}
- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize
{
    NSLog(@"dimension : x= %f y= %f",frameSize.width,frameSize.height) ;
    return frameSize;
}
@end

#19

I realize this is slightly out of date, but I figured I’d ask.

OS: 10.11
Xcode: 7

If I’m not using storyboards, I can successfully set this up - pretty straight forward.

Anyone have a clue how to get this to work with storyboards? Without subclassing NSWindowController? (which seems a bit heavy-handed)

With storyboards, if I drop in an object (either implementing NSWindowDelegate or just with the windowWillResize method) and use IB to set it as the NSWindow delegate, the app hangs/crashes in main.

I realize with storyboards and embedded views, things have changed quite a lot, but I’d still like to know if anyone has successfully addressed this challenge using them - mainly so I can understand the concepts.

Any info much appreciated.

Thank you,
Eric


#20

Okay, I am thoroughly stumped. I have built everything exactly as specified by Adam’s solution on GitHub. Here are the problems as of 2018… OS 10.13.4 and Xcode 10 beta.

In the WindowDelegate.h file, for (bracket)NSWindowDelegate(endBracket*) I get "No type or protocol named ‘NSWindowDelegate’ ". I don’t think this is a deprecated protocol… it still shows up in documentation.

I’m also getting a weird “expected a type” error in the windowWillResize method… not liking (NSWindow *). I have checked the spelling at least 30 times.

I feel like I am missing something. How does *window “know” about WindowDelegate? Am I missing some crucial control-drag-set motion here?

*sorry, the characters above the comma and period make the text in between vanish.

Thanks…