Calling a function from another class in theos(logos) Jailbreak - iphone

I'm trying to run a function from another Class in another Class.
I want to call -(void)updateClock from the Class SBAwayView
Ive tried [[%c(SBAwayDateView) sharedInstance] updateClock];
Ive also tried [%c(SBAwayDateView) updateClock];
but I can't get it to work. (the SpringBoard crashes and I'm in safemode)
Below is the SBAwayDateView Class
%hook SBAwayDateView
-(void)updateClock
{
//do some stuff
//run %orig;
%orig;
}
%end
How can I run -(void)updateClock in SBAwayView Class below?
%hook SBAwayView
-(void)updateInterface
{
//do some stuff
//How can I run -(void)updateClock here?
//run %orig;
%orig;
}
%end
Thanks in advance.

SBAwayDateView doesn't have sharedInstance nor updateClock class methods.
In cases when you are working with class that is not a singleton you need to either find valid instance of this class in some other class - it might contain it in instance variable or return from some method. Or you can hook init method and save somewhere instances yourself. Depends on what you want to do.
In your case SBAwayView has instance variable SBAwayDateView *_dateHeaderView - problem solved
%hook SBAwayView
-(void)updateInterface
{
//do some stuff
SBAwayDateView* dateView = MSHookIvar<SBAwayDateView*>(self, "_dateHeaderView");
[dateView updateClock];
//run %orig;
%orig;
}
%end

Related

Facebook loginViewFetchedUserInfo is called twice

I am using facebook SDK 3.0 in my app. The delegate method is called twice when after logging to facebook.
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
//loginThroughFb=TRUE;
NSString *userId=[[NSString alloc] initWithString:[user id]];
[self soapCallForLogin:#"" password:#"" deviceId:#"" fbid:userId];
NSLog(#"%#",userId);
[userId release];
}
I tried 'HelloFacebookSample' project and the method is called only once.
So I guess the best solution for such case is to keep a reference to the last user object and compare it to the new object you get the next call, and if they're equal you can just ignore that call.
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user {
if (![self isUser:cachedUser equalToUser:user]) {
cachedUser = user;
/// Do something
}
}
- (BOOL)isUser:(id<FBGraphUser>)firstUser equalToUser:(id<FBGraphUser>)secondUser {
return
[firstUser.objectID isEqual:secondUser.objectID] &&
[firstUser.name isEqual:secondUser.name] &&
[firstUser.first_name isEqual:secondUser.first_name] &&
[firstUser.middle_name isEqual:secondUser.middle_name] &&
[firstUser.last_name isEqual:secondUser.last_name] &&
...
}
I also had this problem. I managed to fix it with an ugly hack, but it works. I keep a counter in the FBLoginView delegate. When the fetchedUserInfo is called, I check the counter. If it is greater than zero, return. Otherwise, do two things -
1. increment the message counter
2. Fire a delayed event that zeroes the message counter again.
So your fetchedUserInfo method will look like this:
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
if ([self messageCounter] >0)
return;
else
{
self.messageCounter++;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
[self setMessageCounter:0];
});}
// Do whatever you were going to do }
Fixed in FB SDK 3.8 released on Sept 18 2013. The delegate methods are now called once per login regardless of how many times the repeated logging out and back in occur.
I was also able to reproduce this on FB SDK 3.7.1 and within their own sample program "Scrumptious"
As mentioned (at least for me) this only happens after:
Logging in once
Logging out
Logging back in (Now it happens)
What is interesting is the order of calls on re-logins:
On the first login I the calls I see are:
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView;
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user;
On the 2nd (and later) logins I see:
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user;
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView;
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user;
Which gives a handy little workaround of setting a flag in the middle method like so:
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
// Set flag
self.isFirstLoginDone = YES;
}
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user {
// Check
if(self.isFirstLoginDone) {
// Execute code I want to run just once
NSLog(#"fetched");
}
// Don't forget to clear the flag (I guess it shouldn't matter if everything is cleaned up)
self.isFirstLoginDone = NO;
}
There could be another reason, which i jsut faced.
My situation:
ViewController A has a login (With fbloginview and its delegate set)
User chooses to register, moves to ViewController B with another fbloginview and its delegate set.
The above makes the delegate fire twice.
I have fixed this by setting delegate to nil on ViewWillDisappear in ViewController A.
-(void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
fbLoginButton.delegate=self;
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
fbLoginButton.delegate=nil;
}
I used this simple trick :
(Define an int facebookCounter in your interface)
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
user:(id<FBGraphUser>)user {
if (self.facebookCounter==0) {
self.facebookCounter++;
return;
}
//Do stuff here
}
I needed to add thread safety in this method. A simple class variable did not work. The following two options will work, depending on the use case-
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView user:(id<FBGraphUser>)user {
//self.executedOnce = NO; in the init method of this class
#synchronized(self){
if(!self.executedOnce) {
//do something once per init of this class
self.executedOnce = YES;
}
}
//OR- This will only execute once in the lifetime of the app, thus no need for the executedOnce flag
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//do something once per lifetime of the app
});
}
just in the loginViewFetchedUserInfo method set the delegate of the loginView to nil. then it can never be called. and if you need the login again, set the delegate to the correct object.

How to stub out the return value on a class based method using ocmock

I'm writing a test to verify location services are started when a button click occurs. This requires a very simple if statement to make sure the phone has location services available.
A working test right now looks like this
- (void)testStartUpdatingLocationInvokedWhenLocationServicesAreEnabled
{
[[[self.locationManager stub] andReturnValue:[NSNumber numberWithBool:true]] locationServicesEnabled];
[[self.locationManager expect] startUpdatingLocation];
[self.sut buttonClickToFindLocation:nil];
[self.locationManager verify];
}
The now tested implementation looks like this
- (IBAction)buttonClickToFindLocation:(id)sender
{
if ([self.locationManager locationServicesEnabled])
{
[self.locationManager startUpdatingLocation];
}
}
All good except the method was deprecated in iOS 4.0. So now I need to use the Class Method [CLLocationManager locationServicesEnabled] instead.
The problem is I can't seem to find if ocmock supports this functionality and if it doesn't how should I get around this issue for now.
hmmm, you could use methodExchange. Just make sure you exchange the method back to original after your done with it. It seems hacky, but I haven't found a better solution. I have done something similar for stubbing [NSDate date]
#implementation
static BOOL locationManagerExpectedResult;
- (void)testStartUpdatingLocationInvokedWhenLocationServicesAreEnabled
{
locationManagerExpectedResult = YES;
method_exchangeImplementations(
class_getClassMethod([CLLocationManager class], #selector(locationServicesEnabled)) ,
class_getClassMethod([self class], #selector(locationServicesEnabledMock))
);
[self.sut buttonClickToFindLocation:nil];
}
+ (BOOL)locationServicesEnabledMock
{
return locationManagerExpectedResult;
}
#end
EDIT: I thought you were verifying, but it seems like you are stubbing. Updated code
The simplest approach is to override locationServicesEnabled in a category in your unit test class:
static BOOL locationServicesEnabled = NO;
#implementation CLLocationManager (UnitTests)
+(BOOL)locationServicesEnabled {
return locationServicesEnabled;
}
#end
...
-(void)tearDown {
// reset to default after each test
locationServicesEnabled = NO;
[super tearDown];
}
It will override the superclass method only at test time, and you can set the static global to an appropriate value in each test.
Alternatively, you could wrap the check in your own instance method, and use a partial mock.
In the class under test:
-(BOOL)locationServicesEnabled {
return [CLLocationManager locationServicesEnabled];
}
In your test:
-(void)testSomeLocationThing {
MyController *controller = [[MyController alloc] init];
id mockController = [OCMockObject partialMockForObject:controller];
BOOL trackingLocation = YES;
[[[mockController stub] andReturnValue:OCMOCK_VALUE(trackingLocation)] locationServicesEnabled];
// test your controller ...
}
I don't think it does. The only approach I can think of would be to use a partial mock and then use runtime calls to swizzle in the implementation you need.
Doable, but complex.
A more pattern orientated solution might be to extract the checking for location services out to sit behind a protocol. Then you can simply use a mock for the protocol's implementation during testing to return YES or NO as your require. As the actual implementation would do nothing but return [CLLocationManager locationServicesEnabled] you could get away with not testing it.
This is supported by OCMock:
[[[[mockLocationManagerClass stub] classMethod] andReturnValue:OCMOCK_VALUE(YES)] locationServicesEnabled];

Wait for MKReverseGeocoder to provide address

Is there a way to wait for geocoder to invoke didFailWithError or didFindPlaceMark?
My problem is that i have to call a method that receives coordinate and returns placemark holding the address. But when i call [myGeocoder start] code continues and i get an empty placemark.
My code is:
- (MKPlasemark*) getAddress:(CLLocationCoordinate2D) coordinate
{
[self startGeocoder:coordinate];
return self.foundPlasemark;
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFindPlacemark:(MKPlaseMark*)plasemark
{
self.foundPlasemark=plasemark;
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFailWithError:(NSError*)error
{
self.foundPlasemark=nil;
}
I tryed to perform sleep() whyle one of the following methods invoked, but it didn't work.
I think you are going about it the wrong way, there is no reason to block, what you have to do is have that method return void, and in the class that is handling the geocoding, define a protocol that has a method say -(void)didReceivePlacemark:(id)placemark, placemark can be nil or some placemark, and it is called when the geocoder returns. You also make a delegate property for your class so anyone can subscribe to the protocol... Then in the calling class subscribe to the protocol and implement the method...heres a bit more on protocols
Hope that helps
Here is an example:
So the interface of your class that does the geocoding will look something like this
#protocol GeocoderControllerDelegate
-(void)didFindGeoTag:(id)sender; // this is the call back method
#end
#interface GeocoderController : NSObject {
id delegate;
}
#property(assign) id <GeocoderControllerDelegate> delegate;
Then in the implementation you would see something like this
- (void) getAddress:(CLLocationCoordinate2D) coordinate
{
[self startGeocoder:coordinate];
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFindPlacemark:(MKPlaseMark*)plasemark
{
[delegate didFindGeoTag:plasemark];
}
- (void)reverseGeocoder:(MKReverseGeocoder*)geocoder didFailWithError:(NSError*)error
{
[delegate didFindGeoTag:nil]
}
In the calling class, all you have to set is the delegate property of the GeocoderClass, and implement the protocol, the implementation might look somethign like
-(void)findMethod
{
GeocoderController *c=...
[c setDelegate:self];
[c findAddress];
//at this point u stop doing anything and just wait for the call back to occur
//this is much preferable than blocking
}
-(void)didFindGeoTag:(id)sender
{
if(sender)
{
//do something with placemark
}
else
{
//geocoding failed
}
}

#selector in objective-c not behaving as expected

I am a little perplexed and I have been working on this for hours and googling without any real leads. I want to create a callback in objective-c for my iPhone app utilizing the #selector.
Class 1:
- (void) someMethod {
// create selector
SEL successCallback = #selector(successMethod);
// call some service with caller and selector
[class2 dispatchSomeEvent:self callback:successCallback];
// here's the call back method
- (void) successMethod {
NSLog(#"Callback success");
}
}
Class 2:
// some event
- (void) dispatchSomeEvent:(id) caller selector:(SEL) successCallback {
// catch the event and execute callback
if ([caller respondsToSelector:successCallback]) {
[caller successCallback];
}
}
The conditional respondsToSelector will pass but the callback on the next line will fail. HOWEVER, if I would do like this:
// catch the event and execute callback
if ([caller respondsToSelector:successCallback]) {
[caller successMethod];
}
So instead of using the selector I passed, I type in the method name directly... and it works!
The error I get is this:
unrecognized selector sent to instance
0x6c37f70
What is going on here??
Thanks in advance!
You should call your selector using -performSelector method:
if ([caller respondsToSelector:successCallback]) {
[caller performSelector:successCallback];
}

Searching for the Right Pattern (iPhone/Objective C)

EDIT: It was suggested to me that I implement the strategy pattern (http://en.wikipedia.org/wiki/Strategy_pattern), which I think I would do as several objects that implement a delegate protocol in Objective-C. This accomplishes the encapsulation I want while still allowing me to have a generic view controller in memory.
I have a class called DetailViewController that displays information about various types of data - waypoints, trails, maps, photos.
Right now, this class is 1400 lines long and it has some messy switch statements. For example:
- (void) changeMiniView:(id)sender {
if (self.track) {
[self changeTrackMiniView:[sender selectedSegmentIndex]];
} else if (self.waypoint) {
[self changeWaypointMiniView:[sender selectedSegmentIndex]];
} else if (self.photo) {
[self changePhotoMiniView:[sender selectedSegmentIndex]];
} else if (self.map) {
[self changeMapMiniView:[sender selectedSegmentIndex]];
}
}
This would be a lot neater if I made subclasses of DetailViewController, but my conundrum is I would like to keep the viewController in memory and just change certain elements, so I can have crisp transitions, particularly on 3G phones.
I feel like if I want my code to be neat, I have to take a performance hit.
Have the current view in a field in your object (rather than one field for every type of miniview you have), and implement changeMiniView for each of them.
Then your method would look like:
- (void) changeMiniView: (id)sender {
[self.currentMiniView changeMiniView: [sender selectedSegmentIndex]];
}
How about using selector?
- (void)viewDidLoad {
if (self.track) {
sel = #selector(changeTrackMiniView:);
} else if (self.waypoint) {
sel = #selector(changeWaypointMiniView:);
} else if (self.photo) {
sel = #selector(changePhotoMiniView:);
} else if (self.map) {
sel = #selector(changeMapMiniView:);
}
}
- (void)changeTrackMiniView:(id)sender {
....
}
- (void)changeMiniView:(id)sender {
[self performSelector:sel withObject:sender];
}