How to add another parameter to an existing method - objective-c

I have a category NSObject+Utilities which contains all kinds of tool methods I use in my projects. Unfortunately I have to add one more parameter to a method that returns NSColor.
Here an Example:
- (NSColor*) ccBlueLight {
return [self libMakeAColor :0.000f :0.535f :1.0f :1.000f];
}
The last parameter (1.000f) is responsible is for transparency. When I created this method I didn´t think of transparency and I fixed it to 1.000f. Since I´m using these cc Colors in different projects I cannot simply add another parameter without getting errors in the other projects when using them.
Is there a way to add the transparency parameter without problems?

Write a new method with transparency parameter:
- (NSColor*) ccBlueLight:(CGFloat)transparency {
return [self libMakeAColor :0.000f :0.535f :1.0f :transparency];
}
And change the implementation of existing method to use default value.
- (NSColor*) ccBlueLight {
return [self ccBlueLight:1.000f];
}
Note that these two are different methods. The old one's signature is not changed and there is no need to change the callers of old one.

Is there anything speaking against simply adding a second method? So that one project could use the original and the other one the new method.
- (NSColor *) ccBlueLightWithAlpha:(NSNumber *)alpha
{
return [self libMakeAColor :0.000f :0.535f :1.0f :[alpha floatValue];
}

Like this?
- (NSColor*) ccBlueLight {
return [self libMakeAColorRed:0.000f green:0.535f blue:1.0f];
}
- (NSColor*) ccBlueLightWithAlpha:(CGFloat)alpha {
return [self libMakeAColorRed:0.000f green:0.535f blue:1.0f alpha:alpha];
}

Related

How to extend initWithWindowNibName for an NSWindowController?

I'm not sure I am using the correct terminology, but I want to extend and existing method for a class. I want to be able to call
[[CustomWindowViewController alloc] initWithWindowNibName:#"Something" withObject:object];
I want to implement all of the default functionality, of initWithWindowNibName, but then also pass the object as well.
Thanks
Chet
Figured it out
- (id)initWithWindowNibName:(NSString *)windowNibName withObject:(NSObject*)object {
self = [super initWithWindowNibName:windowNibName];
// custom stuff
return self;
}

How to refresh UICollectionViewCell in iOS 7?

I am trying to develop my app in Xcode 5 and debug it under iOS 7 environment.
I have a customized UICollectionViewLayoutAttributes.
I plan to do something after long pressing on UICollectionViewCell, so I override the method in UICollectionViewCell.m
- (void)applyLayoutAttributes:(MyUICollectionViewLayoutAttributes *)layoutAttributes
{
[super applyLayoutAttributes:layoutAttributes];
if ([(MyUICollectionViewLayoutAttributes *)layoutAttributes isActived])
{
[self startShaking];
}
else
{
[self stopShaking];
}
}
In iOS 6 or below, - applyLayoutAttributes: is called after I call the statements below.
UICollectionViewLayout *layout = (UICollectionViewLayout *)self.collectionView.collectionViewLayout;
[layout invalidateLayout];
However, in iOS 7, - applyLayoutAttributes: is NOT being called even if I reload the CollectionView.
Is that a bug which is gonna be fixed by Apple later on, or I have to do something?
In iOS 7, you must override isEqual: in your UICollectionViewLayoutAttributes subclass to compare any custom properties that you have.
The default implementation of isEqual: does not compare your custom properties and thus always returns YES, which means that -applyLayoutAttributes: is never called.
Try this:
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
}
if (!other || ![[other class] isEqual:[self class]]) {
return NO;
}
if ([((MyUICollectionViewLayoutAttributes *) other) isActived] != [self isActived]) {
return NO;
}
return YES;
}
Yes. As Calman said you must override isEqual: method to compare custom properties that you have. See the apple documentation here
If you subclass and implement any custom layout attributes, you must also override the inherited isEqual: method to compare the values of your properties. In iOS 7 and later, the collection view does not apply layout attributes if those attributes have not changed. It determines whether the attributes have changed by comparing the old and new attribute objects using the isEqual: method. Because the default implementation of this method checks only the existing properties of this class, you must implement your own version of the method to compare any additional properties. If your custom properties are all equal, call super and return the resulting value at the end of your implementation.
In this case, the most efficient method would be
- (BOOL)isEqual:(id)other {
if (other == self) {
return YES;
}
if(![super isEqual:other]) {
return NO;
}
return ([((MyUICollectionViewLayoutAttributes *) other) isActived] == [self isActived]);
}

How to pass parameters using #selector

I need to pass parameters with #selector and here is the method that i need to call using selector:
-(void)clickedInfo:(NSString *)itemIndex{
// some work with itemIndex
}
I know that what i can do is to use an intermediate method as described here.
This approach doesn't work in my case because im adding the target to the uibutton in the cellForItemAtIndexPath method for the collectionView.
The parameter that i need to pass to the clickedInfo method is indexPath.row
and i can not obtain this parameter in an intermediate method.
Thanx in advance
So you want to store some information that can be accessed by the action of a button. Some options are:
Use the tag property of the control. (can only store an integer)
Subclass UIButton and use that class for the button. The class can have a field that stores the information.
Use associated objects (associative references) to attach an object to the button. This is the most general solution.
You can use the performSelector:withObject: selector to pass an object.
Example:
[self performSelector:#selector(clickedInfo:) withObject:myIndex];
- (void) clickedInfo:(NSString *)itemIndex{
// some work with itemIndex
}
Edit: Should be just #selector(clickedInfo:) rather than what I had before.
Edit: Using #newacct 's suggestion, I'd recommend doing something similar to the following:
- (UITableViewCell *)tableView:(UITableView)tableView cellForRowAtIndexPath:(NSIndexPath)indexPath
{
button.tag = indexPath.row;
[button performSelector:#selector(clickedInfo:)];
// or
[button addTarget:self action:#selector(clickedInfo:) forControlEvents:UITouchUpInside];
}
- (void) clickedInfo:(id)sender
{
int row = sender.tag;
// Do stuff with the button and data
}
this is addressed lots of places, but it is easier to answer than to point you there:
[someObject performSelector:#selector(clickedInfo:) withObject:someOtherObject];
where someObject is the receiver and someOtherObject is the parameter passed to clickedInfo

Objective-C: sortDescriptorsDidChange argument?

I don't get why sortDescriptorsDidChange takes an argument oldDescriptors if it is never used in the method.
- (void)tableView:(CPTableView)aTableView sortDescriptorsDidChange:(CPArray)oldDescriptors {
[result sortUsingDescriptors:[aTableView sortDescriptors]];
[aTableView reloadData];
}
What am I missing ?
sortDescriptionDIdChange is a delegate, so you can implement your own behavior for it.
For example, you could use oldDescription along with the new description to manually calculate the changes and provide a nice animation for them. Or to implement specific behavior if the order didn't change etc. etc.

event scope

Given
#interface Canvas:NSView {
NSNumber * currentToolType;
...
}
declared in my .h file
and in the .m file
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
currentToolType=[[NSNumber alloc]initWithInt:1];
}
return self;
}
and further down
-(void)mouseUp:(NSEvent *)event
{
NSLog(#"tool value in event: %d",[currentToolType intValue]);
//rest of code
}
-(NSBezzierPath *)drawPath:(NSRect)aRect
{
NSLog(#"tool value in draw: %d",[currentToolType intValue]);
//rest of drawPath method code that uses the value of currentToolType in a switch statment
}
-(IBAction)selectToolOne:(id)sender
{
[currentToolType release];
[currentToolType = [[NSNumber alloc]initWithInt:0];
}
-(IBAction)selectToolTwo:(id)sender
{
[currentToolType release];
[currentToolType = [[NSNumber alloc]initWithInt:1];
}
The action methods are the only place where currentToolType is changed. But, for some reason, it seems to be a different instance of currentToolType in the mouseUp. I did not write (or synthesize) accessors for the var as it is used only by itself. I noticed that initWithFrame is called twice - I'm assuming it's for the parent window and the NSView?
What am I missing?THANKS!
This is an XCode generated Document based app using COCOA and Obj-C. I'm new at both.
You mention that initWithFrame: is called twice. Your initWithFrame: should only be called once (unless you happen to have two Canvas views).
Is it possible you have the Canvas view in your nib/xib file and are also creating another in code (with alloc/initWithFrame:)?
In which case you have two Canvas objects. You probably have one hooked up to your controls and the other one is in the window (and thus responding to the mouseUp: and it is giving you the same value every time).
If you have the Canvas view setup in IB, you can fix this problem by removing your code that is creating the second one.
You've probably run in to a special case: NSNumber could have cached instances to represent commonly-used numbers.
Two observations, though:
You're wasting a whole lot of memory using NSNumber when you could be simply using NSIntegers or maybe an old-fashioned enumerated type, completely avoiding the object overhead.
You never actually showed your code for when you look at the instances of NSNumber; without it, there's not really enough information here to answer your question.