use OCMockito to test category class method - objective-c

I have a UIColor category that has a class method
+(UIColor *)appropriateTextColorForBackground:(UIColor *)background
{
//...get brightness value
if (brightness > 127.5f)
return [UIColor blackColor];
else
return [UIColor whiteColor];
}
I want to test with OCMockito using this in my test class
-(void)testAppropriateColorWithBlackShouldReturnWhiteColor
{
Class color = mockClass([UIColor class]);
[color appropriateTextColorForBackground:black];
assertThat([color testColorWithColor:black], is([UIColor whiteColor]));
}
but I get the error
test failure: -: *** -[NSProxy doesNotRecognizeSelector:appropriateTextColorForBackground:] called!
what am I missing? it seems that this should work

I agree with Bryan, that you don't need mock here since you want to test your implementation of category method. As example:
-(void)testAppropriateColorWithBlackShouldReturnWhiteColor
{
UIColor *appropriateColor = [color appropriateTextColorForBackground:black];
assertThat(appropriateColor, is(equalTo([UIColor whiteColor])));
}
You also probably want to have similar test for opposite color. I would probably go further and will use colors that are on the border of change for you brightness calculation (instead of black and white). However someone (not me) could argue that this will expose implementation details which is usually thing to avoid while writing unit test.

Related

j2objc java extends native uicolor

how can i extends the UIColor in java code example like using native methods.
So j2objc able to compile the java class extends with UIColor.
I'm not sure how to code the extends part.
Please help.
You can't with j2objc, as classes must by compilable by a Java compiler (such as javac), and there's no UIColor Java source or class file. That said, it would be easy to create your own color class that can create a UIColor when asked, something like:
class MyColor {
float red, green, blue, alpha;
...
native Object toUIColor() /*-[
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
]-*/;

How to use reference self in Objective-C blocks for animation blocks?

I would ideally like to write code that allows me to determine what animations a desired view performs when a certain function is executed, e.g. (n.b., pseudocode):
- (void)animateView:(UIView *)view withAnimations:(NSArray *)arrayOfAnimationBlocks
The above (i.e., desired) function would go through a series of animations in sequence and would not perform each animation until the previous animation has fully been executed. I would also be able to add and remove animations to arrayOfAnimationBlocks during runtime.
To do something like this, I am trying to use the following:
[UIView animateWithDuration:duration animations:animationBlock completion:completionBlock];
and am passing all parameters (duration, animationBlock, completionBlock) when the function is called.
However...
it seems like you cannot access self from within the animationBlock? My animation block contains:
void (^animationBlock)(void) = ^
{
NSLog(#"[^animationBlock]");
[self.viewToAnimate setBounds:CGRectMake(self.viewToAnimate.bounds.origin.x, self.viewToAnimate.bounds.origin.y, self.viewToAnimate.bounds.size.width*2, self.viewToAnimate.bounds.size.height*2)];
};
and my completion block contains:
void (^completionBlock)(void) = ^
{
NSLog(#"[^completionBlock]");
[UIView animateWithDuration:duration animations:^{
[self.viewToAnimate setBounds:CGRectMake(self.viewToAnimate.bounds.origin.x, self.viewToAnimate.bounds.origin.y, self.viewToAnimate.bounds.size.width/2, self.viewToAnimate.bounds.size.height/2)];
} completion:^(BOOL finished){
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Animation Complete" message:#"The previous animations should be fully completed." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
alert.alertViewStyle = UIAlertViewStyleDefault;
[alert show];
}];
};
and then I of course have:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) NSLog(#"Cancel pressed.");
else
{
NSLog(#"buttonIndex = %i", buttonIndex);
}
}
In both animationBlock and completionBlock Xcode gives the following red error:
(!) Use of undeclared identifier 'self'
Josh gave the correct answer in his comments, which I'll elaborate on. The following is invalid:
void (^completionBlock)(void) = ^
{ ... [self something] ... };
#implementation Whatever
...
#end
(as is the same thing with the #implementation placed above the definition of completionBlock) because in the scope in which you declare completionBlock there is no variable named self. self exists only within instance methods of a class and refers to the specific instance that has been called — its value isn't knowable ahead of time in the general case.
So what you probably want (assuming non-ARC; cut out the autorelease if relevant) is something like:
#implementation Whatever
- (dispatch_block_t)completionBlock
{
return [[^{ ... [self something] ... } copy] autorelease];
}
#end
Which will dynamically generate a block pointing to the appropriate self and return it in per the normal getter rules. All that'll actually happen at runtime is that the packet of information that represents the outside state going into the block will be generated and stored. There's no code generation or anything like that so don't fret about the cost. However you do need the copy because blocks try to live on the stack and hence aren't safe to return without being moved to the heap, which is what copy achieves in this case.
For the UIView-style completion block you'd similarly want something like:
- (void (^)(BOOL))blockThatTakesABool
{
return [[^(BOOL var){... [self something] ... } copy] autorelease];
}
You seem to have declared global variables and assigned them to the blocks. Therefore the blocks are defined in the global context and there's no self there as self is a (hidden) argument of a method and therefore only exist within methods.
Also it's useless to use block syntax at global scope. You could as well have written functions instead of blocks. The very reason of the existence of blocks is that in C (and C++ and in Objective-C since it is build upon C/C++) it is impossible to declare/define functions in a nested way.
Here's what blocks are for:
void foo() { ... }
void bar()
{
...
aFun(foo);
...
}
the above is legal but
void bar()
{
...
afun( void foo() { ... } );
...
}
is not legal as in C/C++/Objective-C a function cannot be defined inside another function nor inline in an expression.
Many languages let you define functions inline in an expression, which is a very useful thing, especially for functional style programming. But C/C++/Objective-C do not.
That's why blocks have been invented by Apple for Objective-C (and C++ lambdas, very similar to Apple's blocks, were added to C++ in the C++11 redefinition of the language). Blocks are, in fact, anonymous functions that you can define inline in an expression. You would use a block to solve the problem in my second example.
Blocks (and C++ lambdas) provide language native support for the definition of an inline function and the corresponding closure (with a lot of limitations and quirks as closures are also not a native concept in these languages).
They make somewhat easier for you to comply with Greenspun's tenth rule of programming. (/me waiting for someone to realize how useful guaranteed tail call optimization would also be).
If you haven't already you should really read Apple's View Programming Guide. Especially the section on Animations.
Here is the sample code straight from that document:
- (IBAction)showHideView:(id)sender
{
// Fade out the view right away
[UIView animateWithDuration:1.0
delay: 0.0
options: UIViewAnimationOptionCurveEaseIn
animations:^{
thirdView.alpha = 0.0;
}
completion:^(BOOL finished){
// Wait one second and then fade in the view
[UIView animateWithDuration:1.0
delay: 1.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
thirdView.alpha = 1.0;
}
completion:nil];
}];
}
Do you see the part with the completion block? They declare/create the block right inline with the calling function. When you are first starting out you should always look at Apple's code and following them as closely as you can. When you get more experience you can branch out and try other ways to do it.
Hi all: I came across the StackOverflow post Best Way to Perform Several Sequential UIView Animations? today, which includes an answer by user Yang using CPAnimationSequence! Links are below.
GitHub Repository: https://github.com/yangmeyer/CPAnimationSequence#readme
Motivations and Rationale: https://blog.compeople.eu/apps/?p=43
This looks great!

Optimal way to setup UIView in UIViewController?

I'm wondering if my method to setup my UIViewController is optimal or just plain stupid.
I have typedef'ed an enum with some categories. Let's say 6 different categories.
So depending on which category is the selected one. My UIViewController have a switch which will call different method to setup my UIView according to the selected category.
Just wondering if this is a good method to do this, or should I consider creating 6 different UIViewControllers?
A discussion with pro and cons is very much appreciated.
Thanks.
They are basically the same.
Sample code:
switch (self.category) {
case vegetables:
recipe = [[[WebServices sharedInstance].recipeDictionary objectForKey:self.chosenCategory] objectAtIndex:4]; //Needs to be made random
descriptionText.text = recipe.recipeDescription;
[self setupText];
[self setupVegetablesView];
break;
case dairy:
recipe = [[[WebServices sharedInstance].recipeDictionary objectForKey:self.chosenCategory] objectAtIndex:4]; //Needs to be made random
descriptionText.text = recipe.recipeDescription;
[self setupText];
[self setupDairyProductsView];
break;
- (void)setupVegetablesView
{
descriptionText.textColor = [UIColor colorWithRed:0/255.0 green:103/255.0 blue:55/255.0 alpha:1];
background.image = imageBackgroundVegetables;
topBar.image = topBarForVegetables;
subtitle.image = subtitleImageVegetables;
subtitleLink.image = subtitleLinkBarVegetables;
...
}
Depends on your situation. If the view controllers are similar, than this makes sense. But if they are completely different from each other, use separate subclasses.
I would implement it as following
• i would several UIView derived class each one for the type of UIView that i need
For example, i would have VegatableView and DiaryView
• each one of these view will have the same base class of for example MyBaseView
• MyBaseView will have a function called setup this function will need to be implemented in each of my derived classes (vegetable and diary)
• depending on your enum i would create one of these concrete classes and call the setup function
Example:
switch (self.category) {
MyBaseView recipe;
case vegetables:
//Create an instance of VegetableView
recipe = [[VegetableView alloc] init];
break;
case dairy:
//Create an instance of DiaryView
recipe = [[VegetableView alloc] init];
break;
}
//Call setup for the created view
[recipe setup];
//Setup function in vegetableView.m
- (void)setup
{
//Do some vegetable setup stuff
}
//Setup function in diaryView.m
- (void)setup
{
//Do some diary setup stuff
}
In this way, i would minimize the different code, i would make the parameter equal for both the types of view
Also adding new views will be rather easy, just subclass MyBaseView and implement a setup function that is specialized for your new view
Hence increase the objects decoupling and reducing complexity

How does one know when it's safe to use a parent method in NS subclasses?

As an example, when I'm using an NSMutableDictionary, I know it inherits all the methods of NSDictionary, but how can I know/trust that it has overridden the behavior of those methods if I want to use NSDictionary methods (such as +dictionaryWithObjectsAndKeys) to create my mutable dictionary instance?
More generally, is it the Framework's responsibility to make sure subclasses don't blindly inherit methods that can potentially break instances of the subclass if used? Or is it the coder's responsibility to know not to use them? If Square inherits from Rectangle, and via inheritance I can call
Square *newSquare = [[Square alloc] init];
[newSquare setWidth:3 andHeight:6]; //instead of -(void)setSide:(int)side
I've "broken" the square and other methods which depend on width being equal to height will not work now. What are the rules of the game?
The rule would be only expose what you would allow to be override it means, put on your interface what is really public. When necessary explicitly state that when overriding an specific method call at some point [super methodName].
On your example you would override the method - (void)setWidth:(int)width andHeight:(int)height, and you would like to throw an error if width != height. Or you could also throw an error and force the user to only use - (void)setSide:(int)side.
For example you could do:
// If you want to test and accept cases when width == height
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(width == height, NSLocalizedString(#"This is a Square. Width has to be height.", nil));
[super setWidth:width andHeight:height];
// Or
[self setSide:width];
}
// Or if you want to completely prohibit the usage of the method
- (void)setWidth:(int)width andHeight:(int)height {
NSAssert(NO, NSLocalizedString(#"This is a Square! Please use - (void)setSide:(int)side method.", nil));
}
If you would like to throw some errors and warnings at compilation time, you could use on the declaration of your methods, some of the macros defined on NSObjCRuntime.h.
I wouldn't trust the parent convenience method to call your inheriting init method. For example, that dictionary method could be defined as:
+ (id)dictionaryWithObjectsAndKeys:...
{
return [[[NSDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
If that method is defined that way then it won't be even be aware of your implementation.
You'd have to create your own convenience method. Something like would be in your MyDictionary implementation:
+ (id)myDictionaryWithObjectsAndKeys:...
{
return [[[MyDictionary alloc] initWithObjectsAndKeys:...] autorelease];
}
--
Also...
You probably should inherit Rectangle from Square. Inheritance is additive. You can describe Square with one size (width), but for Rectangle you have two sizes (width, height).

Is there somethone wrong with my Object Scope?

This is a program I'm writing (myself as opposed to copying someone else's and thus not learning) as part of the ObjectiveC and Cocoa learning curve. I want to draw simple shapes on a NSView (limiting it to ovals and rectangles for now). The idea is that I record each NSBezierPath to an NSMutableArray so I can also investigate/implement saving/loading, undo/redo. I have a canvas, can draw on it as well as 2 buttons that I use to select the tool. To handle the path I created another object that can hold a NSBezierPath, color values and size value for each object drawn. This is what I want to store in the array. I use mouseDown/Dragged/Up to get coordinates for the drawing path. However, this is where things go wonky. I can instantiate the object that is supposed to hold the path/color/etc. info but, when I try to change an instance variable, the app crashes with no useful message in the debugger. I'll try to keep my code snippets short but tell me if I need to include more. The code has also degenerated a little from me trying so many things to make it work.
Project: Cocoa document based app
I have the following .m/.h files
MyDocument:NSDocument - generated by XCode
DrawnObject:NSObject - deals with the drawn object i.e. path, color, type (oval/rect) and size
Canvas:NSView - well, shows the drawing, deals with the mouse and buttons
Canvas is also responsible for maintaining a NSMutableArray of DrawnObject objects.
DrawnObject.h looks like this:
#import <Foundation/Foundation.h>
//The drawn object must know what tool it was created with etc as this needs to be used for generating the drawing
#interface DrawnObject : NSObject {
NSBezierPath * aPath;
NSNumber * toolType;//0 for oval, 1 for rectangular etc....
float toolSize;
struct myCol{
float rd;
float grn;
float blu;
float alp;
} toolColor;
}
-(void)setAPath:(NSBezierPath *) path;
-(NSBezierPath *)aPath;
#property (readwrite,assign) NSNumber * toolType;
-(float)toolSize;
-(void)setToolSize:(float) size;
-(struct myCol *)toolColor;
-(void)setCurrentColor:(float)ref:(float)green:(float)blue:(float)alpha;
#end
Canvas.h looks like this
#import
#import "drawnObject.h"
#interface Canvas : NSView {
NSMutableArray * myDrawing;
NSPoint downPoint;
NSPoint currentPoint;
NSBezierPath * viewPath;//to show the path as the user drags the mouse
NSNumber * currentToolType;
BOOL mouseUpFlag;//trying a diff way to make it work
BOOL mouseDrag;
}
-(IBAction)useOval:(id)sender;
-(IBAction)useRect:(id)sender;
-(IBAction)showTool:(id)sender;
-(NSRect)currentRect;
-(NSBezierPath *)createPath:(NSRect) aRect;
-(void)setCurrentToolType:(NSNumber *) t;
-(NSNumber *)currentToolType;
#end
In the Canvas.m file there are several functions to deal with the mouse and NSView/XCode also dropped in -(id)initWithFrame:(NSRect)frame and -(void)drawRect:(NSRect)rect Originally I use mouseUp to try to insert the new DrawnObject into the array but that caused a crash. So, now I use two BOOL flags to see when the mouse was released (clunky but I'm trying....)in drawRect to insert into the array. I've included the method below and indicated where it causes the app to fail:
- (void)drawRect:(NSRect)rect { //This is called automatically
// Drawing code here.
//NSLog(#"Within drawRect tool type is %d", [self currentTool]);
NSRect bounds = [self bounds];
NSRect aRect = [self currentRect];
viewPath = [self createPath:aRect];
//the createPath method uses the tool type to switch between oval and rect bezier curves
if(mouseUpFlag==YES && mouseDrag==YES){
mouseDrag=NO;
//Create a new drawnObject here
DrawnObject * anObject = [[DrawnObject alloc]init];//- WORKS FINE UP TO HERE
NSLog(#"CREATED NEW drawnObject");
[anObject setAPath:viewPath]; //- INSTANT APP DEATH!!!!
NSLog(#"Set a path in drawnObject");
[anObject setToolType:[[NSNumber alloc]initWithInt:5]];
NSLog(#"Set toolType in DrawnObject");
[anObject setToolType:currentToolType];
[myDrawing addObject:anObject];
NSLog(#"Added Object");
}
[[NSColor colorWithCalibratedRed:0.0 green:0.9 blue:0.0 alpha:0.5]set];
[NSBezierPath fillRect:bounds];
[[NSColor lightGrayColor]set];
[viewPath stroke]; //This is so the user can see where the drawing is being done
//Now, draw the paths in the array
[[NSColor blueColor]set];
for(DrawnObject * indexedObject in myDrawing){
[[indexedObject aPath] stroke];//This will do the actual drawing of ALL objects
}
}
I guess this has something to do with object scope or something but I just can not figure it out. As I said, as I've tried things the code has sort of undergone an metamorphosis, sadly not for the better. Like those BOOLS etc.
HELP! Any clever people out there, point me in the right direction please!
ADDED THIS ON:
-(NSBezierPath *)createPath:(NSRect) aRect
{
NSBezierPath * tempPath;
//I need to know what tool
switch(0){ //temporary - this would use the toolType as a selector
case 0:
tempPath = [NSBezierPath bezierPathWithOvalInRect:aRect];
break;
case 1:
tempPath = [NSBezierPath bezierPathWithRect:aRect];
break;
default:
tempPath = [NSBezierPath bezierPathWithOvalInRect:aRect];
break;
}
return tempPath;
}
You said your init method was:
-(void)init {
[super init];
//set default color = black
toolColor.rd=1.0;
toolColor.grn=1.0;
toolColor.blu=1.0;
toolColor.alp=1.0;
//set default size
toolSize=0.8;
//set default toolType
toolType=0;
//oval
NSLog(#"Init %#",self);
}
This is definitely wrong; read up on how to create an init method in the Obj-C guide or by reading sample code. Here's what it should look like:
-(id)init {
if (self = [super init]) {
//set default color = black
toolColor.rd=1.0;
toolColor.grn=1.0;
toolColor.blu=1.0;
toolColor.alp=1.0;
//set default size
toolSize=0.8;
//set default toolType
toolType=0;
//oval
NSLog(#"Init %#",self);
}
return self;
}
By not returning anything from -init, you were preventing the object's creation. Good luck! :-)
Edit: Ashley beat me to it...
What do you mean by “crash”?
Does anything appear in the Debugger Console (⇧⌘R)?
Does a stack trace appear in the Debugger window?
If there's a stack trace, where in your code does it crash?
It just hangs. In the debugger I see:
[Session started at 2008-11-28 14:40:34 +1000.]
2008-11-28 14:40:36.157 CH18Challenge_try2[1893:10b] Mouse Down at (80.000000,285.000000)
2008-11-28 14:40:36.333 CH18Challenge_try2[1893:10b] Mouse Up at (166.000000,217.000000)
2008-11-28 14:40:36.348 CH18Challenge_try2[1893:10b] Init
2008-11-28 14:40:36.349 CH18Challenge_try2[1893:10b] CREATED NEW drawnObject
[Session started at 2008-11-28 14:40:36 +1000.]
Loading program into debugger…
GNU gdb 6.3.50-20050815 (Apple version gdb-962) (Sat Jul 26 08:14:40 UTC 2008)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-apple-darwin".Program loaded.
sharedlibrary apply-load-rules all
Attaching to program: `/Users/johan_kritzinger/Documents/Cocoa/CH18Challenge_try2/build/Debug/CH18Challenge_try2.app/Contents/MacOS/CH18Challenge_try2', process 1893.
(gdb)
Then I have to force quit to stop it.
We need to see the implementation of setAPath from DrawnObject.m. Also, for the "stack trace" look on the upper left of the debugger--it should list a stack of functions showing where in your code the crash is. Make sure you're running in Debug mode, not Release.
On the command line you can type print-object and you can
set a breakpoint in that line and step through it from there. It seems setAPath is somehow broken
Regards
Friedrich
What you have is not a crash. A crash is when a signal is raised (like EXC_BAD_ACCESS) or an uncaught exception.
What you have seems to be an infinite loop.
You need to use the pause button in the Debugger and see exactly where. I would guess that you have an infinite loop in your setAPath: method. You need to work out why this function is looping indefinitely.