Method reCalling - iphone

im kinda new to iOS.
I know that a void method i.e
-(void) pressed {
}
can be called this way:
[self pressed];
and viewDidAppear
can be called something like this:
[self viewDidAppear:YES];
I was wandering on how to do it in this method below, or how to re-Call it:
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return [images count];
}

You shouldn't call -(void)viewDidAppear:(BOOL)animated, it's part of the UIViewController lifecycle and it will be called automatically. As for the other one:
- (NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel
{
return [images count];
}
I never used iCarousel, but it seems to be a method from the Data source, and, as such, shouldn't be called directly as well.

That may me data source method... It is called from a controller.
//And it may be called in the controller as below where delegate is object of some class
iCarousel *iCarouselObj;
if(delegate && [delegate respondsToSelector:#selector(numberOfItemsInCarousel:)])
int items = [delegate numberOfItemsInCarousel:iCarouselObj];
//The below code is just to tell you how to call a method with arguments
iCarousel *iCarouselObj;
int items = [self numberOfItemsInCarousel:iCarouselObj];

Related

Where to put the UIAlert? [duplicate]

I want to check the pasteboard and show an alert if it contains specific values when the view appears. I can place the code into viewDidLoad to ensure it's only invoked once, but the problem is that the alert view shows too quickly. I know I can set a timer to defer the alert's appearance, but it's not a good work-around I think.
I checked the question iOS 7 - Difference between viewDidLoad and viewDidAppear and found that there is one step for checking whether the view exists. So I wonder if there's any api for doing this?
Update: The "only once" means the lifetime of the view controller instance.
There is a standard, built-in method you can use for this.
Objective-C:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([self isBeingPresented] || [self isMovingToParentViewController]) {
// Perform an action that will only be done once
}
}
Swift 3:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if self.isBeingPresented || self.isMovingToParentViewController {
// Perform an action that will only be done once
}
}
The call to isBeingPresented is true when a view controller is first being shown as a result of being shown modally. isMovingToParentViewController is true when a view controller is first being pushed onto the navigation stack. One of the two will be true the first time the view controller appears.
No need to deal with BOOL ivars or any other trick to track the first call.
rmaddy's answers is really good but it does not solve the problem when the view controller is the root view controller of a navigation controller and all other containers that do not pass these flags to its child view controller.
So such situations i find best to use a flag and consume it later on.
#interface SomeViewController()
{
BOOL isfirstAppeareanceExecutionDone;
}
#end
#implementation SomeViewController
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if(isfirstAppeareanceExecutionDone == NO) {
// Do your stuff
isfirstAppeareanceExecutionDone = YES;
}
}
#end
If I understand your question correctly, you can simply set a BOOL variable to recognize that viewDidAppear has already been called, ex:
- (void)viewDidAppear {
if (!self.viewHasBeenSet) { // <-- BOOL default value equals NO
// Perform whatever code you'd like to perform
// the first time viewDidAppear is called
self.viewHasBeenSet = YES;
}
}
This solution will call viewDidAppear only once throughout the life cycle of the app even if you create the multiple object of the view controller this won't be called after one time. Please refer to the rmaddy's answer above
You can either perform selector in viewDidLoad or you can use dispatch_once_t in you viewDidAppear. If you find a better solution then please do share with me. This is how I do the stuff.
- (void)viewDidLoad {
[super viewDidLoad];
[self performSelector:#selector(myMethod) withObject:nil afterDelay:2.0];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
static dispatch_once_t once;
dispatch_once(&once, ^{
//your stuff
[self myMethod];
});
}
By reading other comments (and based on #rmaddy 's answer), I know this is not what OP asked for, but for those who come here because of title of the question:
extension UIViewController {
var isPresentingForFirstTime: Bool {
return isBeingPresented() || isMovingToParentViewController()
}
}
UPDATE
You should use this method in viewDidAppear and viewWillAppear. (thanks to #rmaddy)
UPDATE 2
This method only works with modally presented view controllers and pushed view controllers. it's not working with a childViewController. using didMoveToParentViewController would be better with childViewControllers.
You shouldn't have issues in nested view controllers with this check
extension UIViewController {
var isPresentingForFirstTime: Bool {
if let parent = parent {
return parent.isPresentingForFirstTime
}
return isBeingPresented || isMovingFromParent
}
}
Try to set a BOOL value, when the situation happens call it.
#interface AViewController : UIViewController
#property(nonatomic) BOOL doSomeStuff;
#end
#implementation AViewController
- (void) viewWillAppear:(BOOL)animated
{
if(doSomeStuff)
{
[self doSomeStuff];
doSomeStuff = NO;
}
}
in somewhere you init AViewController instance:
AddEventViewController *ad = [AddEventViewController new];
ad.doSomeStuff = YES;
Not sure why you do this in ViewDidAppear? But if you want doSomeStuff is private and soSomeStuff was called only once, here is another solution by notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doSomeStuff) name:#"do_some_stuff" object:nil];
- (void) doSomeStuff
{}
Then post when somewhere:
[[NSNotificationCenter defaultCenter] postNotificationName:#"do_some_stuff" object:nil];
swift 5
I've tried isBeingPresented() or isMovingToParent.
But It doesn't work.
So I tried below code. and It's work for me!
override func viewDidAppear(_ animated: Bool) {
if (self.isViewLoaded) {
// run only once
}
}
You can use this function in ViewDidLoad method
performSelector:withObject:afterDelay:
it will call that function after delay. so you don't have to use any custom timer object.
and For once you can use
dispatch_once DCD block.Just performSelector in the dispatch_once block it will call performSelector only once when ViewDidLoad is called
Hope it helps

duplicate declaration of method dismissviewdidfinish

Have two actionsheet buttons and one modalviewcontroller on mainviewcontroller in application. Now for two actionsheet buttons and for modalviewcontroller, can i have multiple dismissviewdidfinish method for each
-(void)dismissViewDidFinish:(ModalViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
-(void)dismissViewDidFinish:(Devanagari *)controller1;
{
[self dismissViewControllerAnimated:completion];
}
-(void)dismissViewDidFinish:(English *)controller2;
{
[self dismissViewControllerAnimated:YES];
}
Cause if i add these three methods on mainviewcontroller i get red warning message duplicate declaration of method dismissviewdidfinish.
Any ideas how to solve this kind of situation.
You cannot have the same name for more than 1 method. Use a single dismissViewDidFinish:(UIViewController *)viewController method and then check to see which viewController finished:
- (void)dismissViewDidFinish:(UIViewController *)viewController {
//check to see what kind of class viewController is
//or use tags by setting the viewcontroller.view.tag when creating it
}

App Crash on setting UITableViewCell:textLabel:text

I am creating a split-view iPad application. When the user presses the bar button item in the master view, a modal is presented. This modal has a textfield and has an IBAction to pick up keyboard returns.
On keyboard returns, a new instance of my Farm class is created (code below). This instance is then added to an array that is stored in my delegate. I then try to reload the MasterViewController's table. Upon this reload the application crashes on cell.textLabel.text with a EXC_BAD_ACCESS error.
Farm *current = [delegate.arrayOfFarms objectAtIndex:indexPath.row];
cell.textLabel.text = [current getFarmTitle];
If I ask the array within the delegate how many elements it has, it will indeed show the current amount, even. This is what is bizarre to me about this whole thing: the Farm instances appear to be in existence.
I have instances of AppDelegate in both my MasterViewController and my NewFarmNamingView classes. The instance in the Master is to populate the table. The instance in NewFarm is to add the newly created Farm to the delegate. Code below.
Segments from class NewFarmNamingView:
- (IBAction) keyboardDonePushed:(id)sender
{
// create a Farm and add it to the delegate
NSString *text = newFarmTextField.text;
Farm *newFarm = [[Farm alloc] init];
[newFarm setFarmTitle:text];
[[delegate arrayOfFarms] addObject:newFarm];
[newFarm release];
NSLog(#"Added farm: %#" , text);
// dismiss the view
[self closeView:nil];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// initialize the delegate
delegate = [[UIApplication sharedApplication] delegate];
}
Segments from the class Farm
- (void) setFarmTitle : (NSString *) _farmTitle
{
farmTitle = _farmTitle;
}
- (NSString *) getFarmTitle
{
return farmTitle;
}
// NSCoding Methods
- (void) encodeWithCoder:(NSCoder *)aCoder
{
[aCoder encodeObject:farmTitle forKey:#"kFarmTitle"];
}
- (id) initWithCoder:(NSCoder *)aDecoder
{
farmTitle = [aDecoder decodeObjectForKey:#"kFarmTitle"];
return self;
}
// Initialization method
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
From the runtime reference: "objc_msgsend sends a message to the receiver and expects a simple return value."
I'll bet you anything that what you're returning (if you're returning anything at all) in that class method getTitleFarm is returning an incorrect value. It should be an NSString. Be absolutely sure it is returning an NSString, and not anything else.
If you need to use the respondsToSelector method to see if the class is being released, try:
if([current respondsToSelector:#selector(getFarmTitles)]) {. [current getFarmTitle];
}
else {
NSLog:(#"FAILURE!!");
}
EDIT: maybe you are not retaining or even creating this string at all. In it's initialization, wrap it in a retain]; message

Strange custom delegate actions

Ok -- this one is weird. I have a singleton class that loads information from an XML file. I am using a delegate definition as follows (I define the delegate in a separate header file to make life easier):
#protocol ResourceClassDelegate <NSObject>
#optional
- (void)picturesDidStartLoading;
- (void)picturesDidFinishLoading;
#end
In the resource file, the delegate is defined correctly (I believe):
#property (assign) id<ResourceClassDelegate> delegate;
When using the delegate, the code in the resource class is as follows:
-(void)refreshPiecesOfHistoryWithOperation {
NSLog(#"Operation Started");
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
self.picturePacks = [HistoryXMLParser loadPicturePacks];
[self.allPiecesOfHistory removeAllObjects];
// now lets put all of them in one big file...
for (PicturePack *pp in self.picturePacks) {
for (int ct = 0; ct < [[pp piecesOfHistory] count] ; ct++) {
[self.allPiecesOfHistory addObject:(PieceOfHistory *)[[pp piecesOfHistory] objectAtIndex:ct]];
}
}
NSLog(#"Operation Ended");
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
}
Now... in the class that is listening to the delegate, it is assigned:
- (void)viewDidLoad {
[super viewDidLoad];
// now for the part that makes the loading all happen...
[[ResourceClass sharedResourceClass] setDelegate:self];
}
And in the listening class, the methods are defined....
#pragma mark ResourceClassDelegate
-(void)picturesDidStartLoading {
if (loadingActivity == nil)
loadingActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.view addSubview:loadingActivity];
[loadingActivity setCenter:[self.view center]];
[loadingActivity startAnimating];
}
-(void)picturesDidFinishLoading {
if (loadingActivity != nil) {
[loadingActivity stopAnimating];
[loadingActivity removeFromSuperview];
}
[self.tableView reloadData];
}
Now for the problem... every single time, in the listening class, the method (void)picturesDidFinishLoading is called. The method (void)picturesDidStartLoading never is called.
When I debug the code, in the resource class, the line
if ([delegate respondsToSelector:#selector(picturesDidStartLoading)])
[delegate picturesDidStartLoading];
never reaches the delegate method call - even if I remove the if statement. The line
if ([delegate respondsToSelector:#selector(picturesDidFinishLoading)])
[delegate picturesDidFinishLoading];
is always called.
any ideas?
Ok -- I figured it out....
The delegate was nil during the first call. The reason it is nil is because the function using the delegate was called in the source during the init method. The init method was not complete when the first test of the delegate was performed. At this time the delegate was nil because it is not instantiated until the the init method completes. The reason the second test of the delegate worked is because I submitted the process using an NSOperationQueue.
To fix the problem I have to move things around a bit... it's all about the timing!
Well now that was fun....
That's weird, try to remove #optional in the protocol declaration, and see if you get some warnings.
Try to print a log inside the method as well, other than that it looks fine.

What's with [UITableView reloadData]?

I have an application that has a UITableView. This UITableView is populated by an NSMutableArray being held (as a property) in the appDelegate. You can think of this as an email window. It lists messages in a subclassed UITableViewCell. When a new message appears, I have all the code done which downloads the message, adds the data to the appDelegate's NSMutableArray which holds all of the messages. This code is working fine.
Now, once the new message is downloaded and added to the array, I am trying to update my UITableView using the following code, however - the UITableView's delegate functions do not get called.
The odd thing is when I scroll my UITableView up and down, the delegate methods finally get called and my section headers DO change (they show the message count for that section). Shoudn't they update in real-time and not wait for my scrolling to trigger the refresh? Also, the new cell is never added in the section!!
Please Help!!
APPDELEGATE CODE:
[self refreshMessagesDisplay]; //This is a call placed in the msg download method
-(void)refreshMessagesDisplay{
[self performSelectorOnMainThread:#selector(performMessageDisplay) withObject:nil waitUntilDone:NO];
}
-(void)performMessageDisplay{
[myMessagesView refresh];
}
UITableViewController Code:
-(void) refresh{
iPhone_PNPAppDelegate *mainDelegate = (iPhone_PNPAppDelegate *)[[UIApplication sharedApplication] delegate];
//self.messages is copied from appDelegate to get (old and) new messages.
self.messages=mainDelegate.messages;
//Some array manipulation takes place here.
[theTable reloadData];
[theTable setNeedsLayout]; //added out of desperation
[theTable setNeedsDisplay]; //added out of desperation
}
As a sanity check, have you verified that theTable is not nil at that point?
You could try putting a delay on the reloadData call - I had a similar problem when I was trying to get my tableview to update when reordering cells, except that the app crashed if I called reloadData during it.
So something like this might be worth a try:
Refresh method:
- (void)refreshDisplay:(UITableView *)tableView {
[tableView reloadData];
}
and then call it with (say) a 0.5 second delay:
[self performSelector:(#selector(refreshDisplay:)) withObject:(tableView) afterDelay:0.5];
Hope it works...
If you call reloadData from within a dispatched method, make sure to execute it on the main queue.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^(void) {
// hard work/updating here
// when finished ...
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.myTableView reloadData];
});
});
..same in method form:
-(void)updateDataInBackground {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0), ^(void) {
// hard work/updating here
// when finished ...
[self reloadTable];
});
}
-(void)reloadTable {
dispatch_async(dispatch_get_main_queue(), ^(void) {
[myTableView reloadData];
});
}
Have you tried setting a breakpoint in your refresh method just to be sure your messages array has the correct content before calling reloadData?