What I want to do is cause another save anytime saveInBackgroundWithBlock is called in my app. Im doing this to create a "log" of everything that changes and who changed it. I looked into the PFObject.h but I am not sure how to properly write this in Obj-C or where else/how I could do this other than going through and adding it to every single instance. Is this a good way to do it? Or should I stick it out and use the harder way?
- (void)saveInBackgroundWithBlock:(nullable PFBooleanResultBlock)block;
you have multiple ways in order to achieve this kind of functionality:
Create Util class which receive PFObject and PFBooleanResultBlock as parameters this Util class will execute a call to saveInBackgroundWithBlock inside the callback you can implement the additional save that you need. at the end your Util class should look like the following:
#interface ParseUtils : NSObject
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block;
#end
#implementation ParseUtils
+ (void)saveParseObject:(PFObject *)object block:(PFBooleanResultBlock)block {
// if the object is nil or it was not changed return
if (!object || !object.isDirty) return;
[object saveInBackgroundWithBlock:^(BOOL succeeded, NSError * _Nullable error) {
// if no error occured
if (!error){
// HERE YOU SHOULD CALL YOUR ADDITIONAL SAVE...
}
// handle the callback to the calling class
if (block){
block(succeeded,error);
}
}];
}
#end
Another option is to do the same but with singleton (if you created some REST Client singleton for your project)
Another nice option is to create category on top of the PFObject and there to create a method which do exactly the same like the method that of the util
There are more options but i think that it's enough..
if you want to do it as quick as possible use the utilities. if you want to do it with best architecture then go with the category.
Related
I am trying to call a method that checks whether the player is bigger or smaller than the enemy. (this is a fish game)
In EnemyFish.m I am using this method
-(void) compareSize:(Player*)player{
if (self.fSize > player.pSize){
isBigger = true;
}
else{
isBigger = false;
}
}
Then I want to call this method during the update so I am doing this:
-(void) update {
[self compareSize];
//Check to see if bigger than player fish
if( isBigger == true){
//code for if bigger
}else{ //etc. }
I am getting an exception: sharedlibrary apply-load-rules all
not sure what the best way to set up this method would be, and the best way to call it, since [self compareSize] is definately not working.
Any help would be greatly appreciated, Thanks!
------UPDATE----------
What about if I use this
update:(Player *)player{
The problem I was running into here, is how to call this correctly, I wasn't sure how to change this to correctly call the new update method:
[self schedule:#selector(update) interval:1.0f/60.0f];
It is unclear what you are asking, but let's look at your code and see if it helps.
Your first method can be written more concisely as:
- (void) compareSize:(Player *)player
{
isBigger = self.fSize > player.pSize;
}
There is no point in using an if/else to assign a true/false (or YES/NO) value.
Looking at this method raises the obvious question of whether it would be better returning a value rather than assigning to an instance variable. This would look like:
- (BOOL) compareSize:(Player *)player
{
return self.fSize > player.pSize;
}
and now you can use a call to compareSize in an if.
Assuming the second version of compareSize your second method is:
-(void) update
{
//Check to see if bigger than player fish
if ([self compareSize]) // OOPS, no Player
{
//code for if bigger
}
else
{
//etc.
}
}
But this doesn't work as you need an instance of Player to pass to compareSize:, e.g. [self compareSize:somePlayerInstance]. So you now have to ask yourself where you expect the Player to be found; it could be an argument to update (e.g. - (void) update:(Player *)somePlayerInstance), or you might have a method to call which returns a whole collection of players and you need to test against each one, etc., etc. I can't give an answer as I've no idea of your game and algorithm!
Following comment
You must store a reference to your Player object somewhere in your application. If there is only a single player is Player designed as a singleton with a sharedInstance, or similarly named, class method that returns the single instance? If so then your update will contain:
if ([self compareSize:[Player sharedInstance]])
etc.
Another design pattern is to have your application delegate store the reference and to provide a method (or property) for accessing it. Following this pattern (and making up a class MyDelegateApp and property player names) your code might look like:
if ([self compareSize:((MyAppDelegate *)[NSApp delegate]).player])
Yet another model is to create the single player in the application's main XIB/NIB file - etc., etc., there are many application models!
You "simply" (its not simple of course) need to design your application model so that your single player is accessible, one way or another, where you need it...
Your compareSize: method (note the colon) requires a player parameter.
So you need to call it like this:
[someEnemyFish compareSize:somePlayer]
If self is the instance of EnemyFish you want, you can do [self compareSize:somePlayer], but your title seems to indicate self isn't an EnemyFish?
I've got a function called updateTheValue() that I have called using [self updateTheValue] for a while now. Two things happened recently; I added the method calling in the viewDidLoad() method and it spit out a warning saying my class may not respond to this. Second, I want to pass objects to updateTheValue() like strings, but mostly ints, so I declared an NSObject to pass into the method. Can an int fit into an NSObject slot, or what should I use instead?
I would have posted these seperately but they seem to be related since after updating updateTheValue() to accept an NSObject every reference to this function turns out the error that my class "May not respond to -updateTheValue"
You could make your method like this:
-(void)updateTheValue:(NSObject *)anObject
// or use -(void)updateTheValue:(id)anObject
{
if ([anObject isKindOfClass:[NSString class]]) {
// Do your string handling here
}
else if ([anObject isKindOfClass:[NSNumber class]]) {
// Do your number handling here
}
}
Use it like this:
[self updateTheValue:[NSNumber numberWithInt:42]];
I'd suggest doing two different methods though, i.e. updateTheValueWithInt: and updateTheValueWithString: making it easier to read and understand.
Make sure you make the method signature visible before using them, so that the compiler knows what this does.
If you use separate methods you can use int directly without wrapping them into NSNumber objects.
First problem:
updateTheValue() must be declared before you try to call it.
You can either move the definition of function before the calls to it, or add a prototype at the top - eg, add:
(void) updateTheValue;
near the top.
Second problem:
Use an NSNumber, eg [NSNumber numberWithInt:45];
I’m sure this is a simple one, but it’s been elusive so far, and I’m stumped ...
How do I declare an Ivar so that it’s accessible from ALL Classes in a project?
[Don’t know if it matters, but the ivar in question is (an instance of) my Model class, whose data needs to be accessible to various view controllers.]
Best as I can tell from "The Scope of Instance Variables” in The Objective-C 2.0 Programming Language
... this would be by using the “#public” directive.
So I’ve tried this in the #interface block where the ivar is declared:
#interface ...
...
#public
ModelClass *theModel;
#end
... But when I try to refer to “theModel” in a different class, the compiler doesn’t auto-complete, and when I type it in anyway, the compiler shows:
“Error: ‘theModel’ undeclared (first use in this function)”.
I assume this is a question of Scope, and that I haven’t made the ivar available appropriately, but how? Somehow I need to access this, or make its pointer available somehow.
Any ideas would be VERY much appreciated. Many thanks!
Perhaps you forgot to put the instance variable inside the braces of the class where all instance variable declarations go?
#interface Foo : NSObject {
// other instance variable declarations
#public
ModelClass *theModel;
}
// method and property declarations
#end
Also, can you show us the code of how you are trying to access the instance variable from elsewhere? The proper syntax should be:
myFooInstance->theModel
where myFooInstance is a value of type "Foo *"
I make properties available to all views managed by a Tab Bar via a singleton representing my data model. This is efficient and allows all Views access to the data (as well as any other application elements. Creating the singleton is straightforward (there are a ton of examples on S.O.). The you just request the instance and get the property values you need.
Here is a framework fro creating the Singleton. The key points are the static instance and the fact that you do the initialization as [[self alloc] init];. This will ensure the object gets cleaned up correctly. All the methods at the bottom of the class are standard from the SDK Docs to make sure release calls are ignored (because the object is shared globally).
Singleton Boilerplate (ApplicationSettings.m):
static ApplicationSettings *sharedApplicationSettings = nil;
+ (ApplicationSettings*) getSharedApplicationSettings
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedApplicationSettings;
}
+ (id)allocWithZone:(NSZone *)zone
{
#synchronized(self) {
if (sharedApplicationSettings == nil) {
sharedApplicationSettings = [super allocWithZone:zone];
return sharedApplicationSettings; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone
{
return self;
}
- (id)retain
{
return self;
}
- (unsigned)retainCount
{
return UINT_MAX; //denotes an object that cannot be released
}
- (void)release
{
//do nothing
}
- (id)autorelease
{
return self;
}
You cannot access iVars from any other class.
You have to declare a getter/setter method to change or view a variable from another class - what you are really looking for are properties, that make it easier to define and access these getter/setter methods.
In your example above, you'd have the property defined just after the block that defines the local variable in the header file:
#property (nonatomic, retain) ModelClass *theModel;
In the implementation file you'd have the getter/setter created with the #synthesize statement just after the #implementation line:
#synthesize theModel;
Then if you have an instance of your class created, you access the class instance variable like so:
myInstance.theModel = [[[ModelClass alloc] init] autorelease];
The reason #public & #private are in there are to define visibility for subclasses (which, being extensions of that class type also get all the class local variables defined by a superclass), not for any random class.
The standard Objective-C way of doing it is to have a class method that returns the ivar
In your .h file:
+ (id)defaultModel;
and in your .m file:
static ModelClass * defaultModelInstance;
#implementation ModelClass
+ (id)defaultModel {
if (!defaultModelInstance) {
defaultModelInstance = [[ModelClass alloc] init];
}
return defaultModelInstance;
}
#end
although this will need tweaking if you need a specific ivar instead of just "a ivar that's always the same"
this type of design is used by many Cocoa classes i.e. [NSWorkspace sharedWorkspace]
Think a C global variable.
Adding:
extern ModelClass* theModel;
after the #end in the header will make the variable visible anywhere you include the header.
In the ModelClass.cpp file add:
ModelClass* theModel;
before the class implementation.
The variable will still have a value of nil until you allocate and initialize it though and you will be resposible for ensuring that it gets deallocated at the correct time.
THANK YOU ALL for the very helpful discussion on this topic! Clearly there are several ways to approach things here, so this is a very useful assortment of techniques.
Just to let y'all know that in researching this issue further, I ran across a couple of other very helpful pages, listed below. They include mention of the NSNotificationCenter, which I hadn't heard of before; as well as the idea of the "dependency injection" design pattern.
The idea is to keep "low coupling"(1) between the classes, making the code more modular & better for unit testing.
And while the 'notification' pattern sounds like a great idea, in this case it may be a bit overkill, considering that I only need ONE instance of the data model throughout the run of the app, and it doesn't change throughout.
Finally, even though the "#public" compiler directive is well-documented in Apple's Obj-C guide(2), I later found a fascinating edict in a different doc stating that it shouldn't be used! Quoted from Apple's own Cocoa Fundamentals(3):
"Give the proper scope to your instance variables. Never scope a variable as #public as this violates the principle of encapsulation. ..."
(Strange that they don't mention this in their 'Objective-C 2.0' guide where the directive is actually explained.)
Anyway, here are a couple of other links I found to be full of some great insights as well. FYI:
S.O.: "What’s the best way to
communicate between
viewcontrollers?"(4) <<
CocoaWithLove: "Five approaches to
listening, observing and notifying in
Cocoa"(5)
CocoaWithLove: "Singletons,
AppDelegates and top-level data"(6)
Hope these help. Anyway, thank you all again!
Best,
rond
P.S. Yikes! It won't let me post more than one inline hyperlink, so I'm listing them here instead. Obviously, they’re all prefixed by “http://” ... :O
(1): en.wikipedia.org/wiki/Coupling_(computer_science)
(2): developer.apple.com/DOCUMENTATION/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple%5Fref/doc/uid/TP30001163-CH12-TPXREF127
(3): developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/AddingBehaviortoaCocoaProgram/AddingBehaviorCocoa.html#//apple_ref/doc/uid/TP40002974-CH5-SW12
(4): stackoverflow.com/questions/569940/whats-the-best-way-to-communicate-between-viewcontrollers
(5): cocoawithlove.com/2008/06/five-approaches-to-listening-observing.html
(6): cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html
I am using a singleton backbone in my application to handle accuring errors. They will be handled inside the singleton and broadcast a notification throughout the app when the error has been fixed. Anyways this is not what my question is about but when I pass a new error to the singleton object like this
[[SingletonErrors sharederrors] addError:ErrorDictionary_here];
I want ErrorDictionary_here to be a NSMutableDictionary protected by a given #protocol in my code so whenever I give my code to others in my team they get warnings about error information they might have forgotten to pass into the dictionary.
Is this even possible for starters because this is about adding protocols to setters and a getter is much more easy like
-(NSMutableArray< myprotocol > *)getmyError{
}
I hope some one can help me out.
I'm not seeking for passing objects (read class instances) instead of the dictionary just a protocol applied on my dictionary.
It is also possible to implement a protocol through a category like so:
#interface NSMutableDictionary_TD(ErrorExtensions) <ErrorProtocol>
#end
#implementation NSMutableDictionary(ErrorExtensions)
//implement the ErrorProtocol here
#end
If I understand what you're asking, you should be able to do this without too much hassle. In your singleton class SingletonErrors, you should have:
#interface SingletonErrors : NSObject {
// some definitions ...
// The current array of all errors. This can also be an NSMutableSet if you like
NSMutableArray *sharedErrors;
// more definitions ...
}
// some properties ...
#property(nonatomic,retain) NSMutableDictionary<ErrorProtocol> *sharedErrors;
// more properties ...
- (void)addError:(NSMutableDictionary<ErrorProtocol> *)newError;
#end
You should create the protocol to be implemented. In this sample protocol, let's say you want to provide a single method to check whether the object is valid - that is, the dictionary contains all the relevant information.
#protocol ErrorProtocol
- (BOOL)isValid;
#end
You'll then need to subclass NSMutableDictionary so that your class implements the ErrorProtocol protocol:
#interface MyMutableDictionary : NSMutableDictionary <ErrorProtocol> {
}
#end
#implementation MyMutableDictionary
- (BOOL)isValid {
// Do your validity checking here
return YES; // Obviously change this line
}
#end
Then, whenever you throw an error, you can pass in a new instance of MyMutableDictionary to SingletonErrors, and have it call the isValid selector on the MyMutableDictionary, since it's assured that the dictionary will conform to ErrorProtocol and responds to isValid:
- (void)addError:(NSMutableDictionary<ErrorProtocol> *)newError {
if([newError isValid]) {
// Add the new error to the current array of errors
[self.sharedErrors addObject:newError];
// Other code to "broadcast" the error would go here
} else {
// Some code to error out of adding the error would go here
}
}
Overall, what this solution does is:
Hold a NSMutableArray of all errors in SingletonErrors
Each error is an NSMutableDictionary that conforms to ErrorProtocol
The object we use for each error is MyMutableDictionary, a subclass of NSMutableDictionary
The protocol ErrorProtocol defines a method isValid that checks whether the error is OK to be added
The SingletonErrors object calls the isValid method and adds the error appropriately
Thats correct but the doesnt feel nice to me .. my solution merged with tim`s was
#implementation NSMutableArray (myAddition)
- (BOOL)isValid {
// Do your validity checking here
return YES; // Obviously change this line
}
#end
This saves a load of code .. Im a Objective C in blood and fains .. less is better :) .. thanks for your reply anyways because im sure this issue is not a basic objc issue. Its more advanced and i think loads of people will find this topic and see the fix and you fix is 100% right as well so thanks for that !..
My heart is to small to store the loving replies i get here :).
I often find in my iPhone Objective-C unit tests that I want stub out a class method, e.g. NSUrlConnection's +sendSynchronousRequest:returningResponse:error: method.
Simplified example:
- (void)testClassMock
{
id mock = [OCMockObject mockForClass:[NSURLConnection class]];
[[[mock stub] andReturn:nil] sendSynchronousRequest:nil returningResponse:nil error:nil];
}
When running this, I get:
Test Case '-[WorklistTest testClassMock]' started.
Unknown.m:0: error: -[WorklistTest testClassMock] : *** -[NSProxy doesNotRecognizeSelector:sendSynchronousRequest:returningResponse:error:] called!
Test Case '-[WorklistTest testClassMock]' failed (0.000 seconds).
I've had a really hard time finding any documentation on this, but I assume that class methods aren't supported by OCMock.
I found this tip after a lot of Googling. It works, but is very cumbersome:
http://thom.org.uk/2009/05/09/mocking-class-methods-in-objective-c/
Is there anyway to do this within OCMock? Or can someone think of a clever OCMock category object that could be written to accomplish this sort of thing?
Update for OCMock 3
OCMock has modernized its syntax for supporting class method stubbing:
id classMock = OCMClassMock([SomeClass class]);
OCMStub(ClassMethod([classMock aMethod])).andReturn(aValue);
Update
OCMock now supports class method stubbing out of the box. The OP's code should now work as posted. If there is an instance method with the same name as the class method, the syntax is:
[[[[mock stub] classMethod] andReturn:aValue] aMethod]
See OCMock's Features.
Original Answer
Sample code following Barry Wark's answer.
The fake class, just stubbing connectionWithRequest:delegate:
#interface FakeNSURLConnection : NSURLConnection
+ (id)sharedInstance;
+ (void)setSharedInstance:(id)sharedInstance;
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate;
#end
#implementation FakeNSURLConnection
static id _sharedInstance;
+ (id)sharedInstance { if (!_sharedInstance) { _sharedInstance = [self init]; } return _sharedInstance; }
+ (void)setSharedInstance:(id)sharedInstance { _sharedInstance = sharedInstance; }
+ (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate {
return [FakeNSURLConnection.sharedInstance connectionWithRequest:request delegate:delegate];
}
- (NSURLConnection *)connectionWithRequest:(NSURLRequest *)request delegate:(id<NSURLConnectionDelegate>)delegate { return nil; }
#end
Switching to and from the mock:
{
...
// Create the mock and swap it in
id nsurlConnectionMock = [OCMockObject niceMockForClass:FakeNSURLConnection.class];
[FakeNSURLConnection setSharedInstance:nsurlConnectionMock];
Method urlOriginalMethod = class_getClassMethod(NSURLConnection.class, #selector(connectionWithRequest:delegate:));
Method urlNewMethod = class_getClassMethod(FakeNSURLConnection.class, #selector(connectionWithRequest:delegate:));
method_exchangeImplementations(urlOriginalMethod, urlNewMethod);
[[nsurlConnectionMock expect] connectionWithRequest:OCMOCK_ANY delegate:OCMOCK_ANY];
...
// Make the call which will do the connectionWithRequest:delegate call
...
// Verify
[nsurlConnectionMock verify];
// Unmock
method_exchangeImplementations(urlNewMethod, urlOriginalMethod);
}
Coming from the world of Ruby, I understand exactly what you're trying to accomplish. Apparently, you were literally three hours ahead of me trying to do exactly the same thing today (time zone thing? :-).
Anyway, I believe that this is not supported in the way one would desire in OCMock because stubbing a class method needs to literally reach into the class and changes its method implementation regardless of when, where, or who calls the method. This is in contrast to what OCMock seems to do which is to provide you a proxy object that you manipulate and otherwise operate on directly and in lieu of a "real" object of the specified class.
For example, it seems reasonable to want to stub NSURLConnection +sendSynchronousRequest:returningResponse:error: method. However, it is typical that the use of this call within our code is somewhat buried, thus making it very awkward to parameterize it and swap in a mock object for the NSURLConnection class.
For this reason, I think the "method swizzling" approach you've discovered, while not sexy, is exactly what you want to do for stubbing class methods. To say it's very cumbersome seems extreme -- how about we agree it's "inelegant" and maybe not as convenient as OCMock makes life for us. Nevertheless, it's a pretty concise solution to the problem.
Here is a nice 'gist' with a swizzle implementation for class methods: https://gist.github.com/314009
If you modify your method under test to take a parameter which injects the class of the NSURLConnection, then it's relatively easy to pass in a mock that responds to the given selector (you may have to create a dummy class in your test module which has the selector as an instance method and mock that class). Without this injection, you're using a class method, essentially using NSURLConnection (the class) as a singleton and hence have fallen into the anti-pattern of using singleton objects and the testability of your code has suffered.
Link to the blogpost in the question and RefuX gist inspired me to come up with block enabled implementation of their ideas: https://gist.github.com/1038034