UIRefreshControl addTarget action causing "unrecognized selector" error - ios

I have a UITableViewController in which I am implementing a UIRefreshControl for pull to refresh. Everything is working fine, the table is getting populated from my web service. But when I pull down to refresh I get the error:
[MyViewController refreshView]: unrecognized selector sent to instance ...
Which is complaining about the addTarget action here:
UIRefreshControl * refresh = [[UIRefreshControl alloc] init];
[refresh addTarget:self action:#selector(refreshView) forControlEvents:UIControlEventValueChanged];
The error flag on that line in the editor is Undeclared selector 'refreshView'
My refreshView method is simply:
- (void) refreshView: (UIRefreshControl *)refresh {
NSLog(#"test");
}
Any ideas as to why this would be causing the application to crash? (I am running iOS 7.1)

If you declared your method as "refreshView:" (i.e. with a parameter), you need to add a colon to the "#selector" bit.
In other words, one line changes with one character:
[refresh addTarget:self action:#selector(refreshView:) forControlEvents:UIControlEventValueChanged];

Related

Calling a function through UIButton

I am not sure if my code is wrong, but there are no errors while compiling.
I have a refresh button where it refreshes a TableView and here's the following code:
- (IBAction)refreshButton:(UIButton *)sender {
UIButton *refreshButton = [UIButton alloc];
[refreshButton addTarget:self action:#selector(scanBLEDevices:) forControlEvents:UIControlEventTouchUpInside]; }
- (void)scanBLEDevices:(id)sender {
[manager scanForPeripheralsWithServices:#[[CBUUID UUIDWithString:BLEService]] options:nil];
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(stopScan:) userInfo:nil repeats:NO];}
Is there any mistake in this code? I am unsure about this second line, whether this is allowed:
UIButton *refreshButton = [UIButton alloc];
There is no "mistake" in your code, as, like you stated, it complies. The "mistake" here is more than syntax, it's context.
If you are expecting your button to fire and perform your scan,
then you should be calling your method scanBLEDevices: inside your
IBAction method refreshButton:.
In your snippet, by creating a new UIButton in your refresh button method, you are merely assigning an action to a button that has not been initialized yet, and providing no opportunity for the button to be fired (it is created and exists only within this method).
Assuming you have attached your action method correctly in your storyboard, I suggest replacing your simple IBAction method with the following:
- (IBAction)refreshButton:(UIButton *)sender {
[self scanBLEDevices:sender];
}
Because your scanBLEDevices: method requires an id sender, you can pass your button along (since after all you don't use it in the BLE method anway lol).
Hopefully this should help point you in the right direction. Happy coding!
NOTE: If you are unsure about when / where allocation is allowed here, I suggest reading up on some common practices concerning IBActions, targets, and senders when using UIButton elements in your code.
UIButton - UIKit | Apple Developer Documentation

setRightBarButtonItems:animated: crash

I called
[self.navigationItem setRightBarButtonItems:nil animated:YES];
to hide the buttons during refresh operations
Sometimes I caught an exception saying
*** setObjectForKey: object cannot be nil (key: kUINavigationBarAnimationRightViews)
Previously the rightBarButtonItems array contained an item with a custom view - a UISearchBar being a firstResponder.
Calling the following line of code caused the crash
[self.navigationItem setRightBarButtonItems:nil animated:YES];
The solution
Simply calling
self.searchBar resignFirstResponder];
solved the issue

UIRefreshControl + AFNetworking crashes

I'm using AFNetworking 2.x and this UIRefreshControl+AFNetworking category, have a weird problem using a UIViewController with a UITableView as a property, I add a UIRefreshControl with this particular code
CGRect frame = self.mytableView.bounds;
frame.origin.y = -frame.size.height;
UIView *refreshBackgroundView = [[UIView alloc]initWithFrame:frame];
refreshBackgroundView.backgroundColor = [UIColor colorWithRed:239/255.0f green:239/255.0f blue:244/255.0f alpha:1.0f];
self.refreshControl = [[UIRefreshControl alloc]init];
[self.mytableView insertSubview:refreshBackgroundView atIndex:0];
[self.mytableView addSubview:self.refreshControl];
self.refreshControl.tintColor = [UIColor lightGrayColor];
[self.refreshControl addTarget:self action:#selector(getAlertList:) forControlEvents:UIControlEventValueChanged];
[self.mytableView.tableHeaderView addSubview:self.refreshControl];
UIRefreshControl+AFNetworking.h causing a EXC_BAD_ACCESS, when I have a call for my webservice and the user do a segue (the task its not finish), the task continue calling the UIRefreshControl from my dead VC, i have a strong reference for the property self.refreshControl.
The trace on the error leave to this part of the code in AFURLSessionManager.h on the Method:
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
exactly on this lines:
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo];
});
I open a issue to AFNetworking an #matt (AFNetworking creator and maintainer) response was: "Your UIRefreshControl is being deallocated before the task finishes, causing a selector to be sent to an incorrect target. Be sure to keep a strong reference to the control to ensure that it's not released prematurely. " Something that i already know.I already use Instrument to detect the zombie object and all appears to be the UIRefreshControl, any ideas to solve this problem ???
Other advice or comment i had form #matt (AFNetworking creator and maintainer) was "It's the responsibility of the developer to either keep a reference to the control or cancel the associated task before performing the segue. " . I already try to cancel the task before the segue but it's the same problem.
If someone have a idea to do that or have a solution for this problem i would be very happy to listen.
Thx

How do I incorporate TSPopover into my app so it doesn't cause run-time crash?

I am trying to incorporate TSPopover into my iPad app (XCode 4.6, Storyboards with UITabBarController, iOS 6.2). I have copied the TSPopover code into my app, and picked one controller to start with. On one scene, I have the little 'i' in a circle for the user to tap when they need help (it's going to eventually be localized, thus the need for the help). So, I have this code in -viewDidLoad:
if(tfShopOpens.text.length == 0 || shopCloses.text.length == 0) {
/* (below code copied from the TSPopover demo code)
UIButton *topButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[topButton addTarget:self action:#selector(showPopover:forEvent:) forControlEvents:UIControlEventTouchUpInside];
topButton.frame = CGRectMake(10,10, 300, 30);
[topButton setTitle:#"button" forState:UIControlStateNormal];
topButton.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
[self.view addSubview:topButton];
*/
[boHelpStoreHours addTarget:self action:#selector(showPopover:forEvent:) forControlEvents:UIControlEventTouchUpInside];
This is from the .h file:
- (IBAction)bHelpStoreHours:(UIButton *)sender;
#property (strong, nonatomic) IBOutlet UIButton *boHelpStoreHours;
This is from the Connections Inspector:
This is the error I'm getting when I tap this particular button:
2013-04-02 15:49:48.016 saori[5495:c07] -[PreferencesViewController bHelpStoreHours:]: unrecognized selector sent to instance 0x8a6c510
2013-04-02 15:49:48.019 saori[5495:c07] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PreferencesViewController bHelpStoreHours:]: unrecognized selector sent to instance 0x8a6c510'
* First throw call stack:
(0x26fc012 0x19eae7e 0x27874bd 0x26ebbbc 0x26eb94e 0x19fe705 0x9322c0 0x932258 0x9f3021 0x9f357f 0x9f26e8 0x961cef 0x961f02 0x93fd4a 0x931698 0x2b79df9 0x2b79ad0 0x2671bf5 0x2671962 0x26a2bb6 0x26a1f44 0x26a1e1b 0x2b787e3 0x2b78668 0x92effc 0x222d 0x2155 0x1)
libc++abi.dylib: terminate called throwing an exception
The problem I'm having is that I'm not sure everything is connected correctly to make this work. There are NO comments in the TSPopover code to guide me, so I'm guessing what is needed. I have looked in Google and SO... nothing! What is causing the run-time crash? and how do I fix it?
Your bHelpStoresHours: method may not exist in your #implementation. Make sure you have defined the method in your PreferencesViewController.m file.

Exception because of UIRefreshControl

I'm using the UIRefreshControl for the first time and I get an exception during the loading of my refresh control.
Here is my declaration :
self.refreshControl = [[UIRefreshControl alloc] init];
self.refreshControl.tintColor = [UIColor grayColor];
[self.refreshControl addTarget:self action:#selector(refreshView:) forControlEvents:UIControlEventValueChanged];
[self.actualitesTableView addSubview:self.refreshControl];
Here are my functions :
- (void)refreshView:(UIRefreshControl *)sender {
[self performSelectorInBackground:#selector(threadAction) withObject:nil];
}
- (void)threadAction {
[self choixMAJ];
NSLog(#"OK1");
[self.refreshControl endRefreshing];
NSLog(#"OK2");
}
When I use the choixMAJ() method, it works perfectly.
Everything's going right and the OK2 is logged but after that, when the refresh control disapeared, the app crashed with this error :
*** -[__NSArrayM removeObject:]: message sent to deallocated instance 0x655a1a0
I don't understand why.. Any ideas ?
Well, you shouldn't call -endRefreshing on a background thread, for starters. UIKit methods (including that one) should be performed on the main thread. I'm not sure that's actually causing your problem, though.
Thanks shusta, it helps me a lot !
The answer here is correct, and to work around this i did the following.
I setup a timer in the main thread which monitored for a boolean. When you are ready to stop the refresher... set that boolean to true in your sub-thread. The timer will see that and call the endRefreshing function from the main thread.

Resources