How to call presentViewController from inside class
Your class RemoteAPI
does not have a method called presentViewController(). presentViewController()
is a method on a UIViewController
. This is why you are getting the error.
To call presentViewController()
, call back to a UIViewController
instance when your HTTP response finishes.
Inside your else
block of api.getData()
, you can access the error object. Here you can create your alert controller and then present it. This block of code is called a callback, and your view controller should be responsible for creating the alert controller that indicates an error.
Calling presentViewController from custom class
I sometimes create a utilities class to display alerts and such. What I usually do is have my methods for presenting view controllers take the current view controller as a parameter. That approach works pretty well.
EDIT:
Here is an example method from a file Utils.swift in one of my projects. It defines a class function that displays a UIAlertController alert on the current view controller:
class Utils
{
static let sharedUtils = Utils()
class func showAlertOnVC(
targetVC: UIViewController,
var title: String,
var message: String)
{
title = NSLocalizedString(title, comment: "")
message = NSLocalizedString(message, comment: "")
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let okButton = UIAlertAction(
title:"OK",
style: UIAlertActionStyle.Default,
handler:
{
(alert: UIAlertAction!) in
})
alert.addAction(okButton)
targetVC.presentViewController(alert, animated: true, completion: nil)
}
}
The code above defines a class Utils. Note that it does not have any base class, which is Ok in Swift.
Next it defines a public static variable sharedUtils that you can use to get access to the singleton Utils class.
Finally, it defines a class method showAlertOnVC
that can be used to display a UIAlertController alert on top of the current view controller. To use showAlertOnVC
you call it from the current view controller and pass self as the targetVC
parameter.
How can I call presentViewController in UIView class?
Call this function on your button
func infoClick() {
let storyboard: UIStoryboard = UIStoryboard (name: "Main", bundle: nil)
let vc: CampainDetailView = storyboard.instantiateViewControllerWithIdentifier("campainDetailView") as! CampainDetailView
let currentController = self.getCurrentViewController()
currentController?.presentViewController(vc, animated: false, completion: nil)
}
This function will create root view controller
func getCurrentViewController() -> UIViewController? {
if let rootController = UIApplication.shared.keyWindow?.rootViewController {
var currentController: UIViewController! = rootController
while( currentController.presentedViewController != nil ) {
currentController = currentController.presentedViewController
}
return currentController
}
return nil
}
This above code must work, it is working for me in Swift 4.0
Present View Controller from another class
This line:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
Creates a new instance of ViewControllerYoutube
. This ViewController doesn't exist anywhere else but that line, so when you follow it with this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
You're trying to present on a view controller that hasn't yet been presented.
If you want to present from an outside class, you need some way to keep a reference to the view controller you want to present, perhaps in your ActionSheet.h
@property (weak, nonatomic) ViewControllerYoutube *myViewControllerYoutube;
Then assign it when you create your action sheet (assuming you create it in ViewControllerYoutube)
ActionSheet * myActionSheet = [[ActionSheet alloc]init];
myActionSheet.myViewControllerYoutube = self;
Then instead of this:
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[vc presentViewController:vc animated:YES completion:nil];
Call this:
[_myViewControllerYoutube presentViewController:vc animated:YES completion:nil];
UPDATE
Based on our chat, here's how I think we can solve it.
In
ActionSheet.h
:@property (weak, nonatomic) UIViewController *presentingViewController;
In 'ActionSheet.m'
ViewControllerYoutube *vc = [[ViewControllerYoutube alloc]init];
[_presentingViewController presentViewController:vc animated:YES completion:nil];In your AppDelegate:
ActionSheet * actionSheet = [[ActionSheet alloc]init];
UITabBarController * tabController = (UITabBarController *)self.window.rootViewController;
actionSheet.presentingViewController = tabController.selectedViewController;
how to call presentViewController from within a UICollectionViewCell
UITableViewCell should never handle any business logic. It should be implemented in a view controller. You should use a delegate:
UICollectionViewCell subclass:
protocol CustomCellDelegate: class {
func sharePressed(cell: MyCell)
}
class CustomCell: UITableViewCell {
var delegate: CustomCellDelegate?
func didTapShare(sender: UIButton) {
delegate?.sharePressed(cell: self)
}
}
ViewController:
class TableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
//...
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CustomCell
cell.delegate = self
return cell
}
}
extension TableViewController: CustomCellDelegate {
func sharePressed(cell: CustomCell) {
guard let index = tableView.indexPath(for: cell)?.row else { return }
//fetch the dataSource object using index
}
}
Using presentViewController from UIView
Only UIViewController can present another view controller, so if you need to show a viewcontroller from view there are several way, one of them is like this:
make a viewcontroller on which your parent view is situated a delegate of it
ParentView *view = [ParentView new];
...
view.delegate = self;
then, inside ParentView call method of that delegate
- (IBAction)homeButtonPressed:(id)sender {
[self.delegate buttonPressed];
}
and then, inside your VC implement
-(void)buttonPressed {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:vc animated:NO completion:NULL];
}
If you need to keep this code inside UIView and avoid delegation you can do a trick like this (personally i don't like it but it should work)
-(void)buttonPressed{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"ViewController"];
[vc setModalPresentationStyle:UIModalPresentationFullScreen];
[(UIViewController*)self.nextResonder presentViewController:vc animated:NO completion:NULL];
}
Related Topics
Swift - Segue from Button Inside a Cell
How to Know Where Optional Chaining Is Breaking
Changing Font Color of Uibarbuttonitem
Swift Memory Management: Storing Func in Var
Updating a @Published Variable Based on Changes in an Observed Variable
iOS 13, Custom Image, Title and Subtitle in the Presented Uiactivityviewcontroller
How to Check If Core Data Is Empty
Avplayer Can't Resume After Paused + Some Waiting
Instagram Explorer Searchbar and Tableview
Unsafemutablepointer<Void> to Concrete Object Type
Accessibility (Voice Over) with Sprite Kit
Using Animoji/Memoji as Profile Photo
How to Deal with Buffered Strings from C in Swift
Using Xcode to Cross-Compile Swift to Linux
How to Rotate an Arkit 4X4 Matrix Around Y Using Apple's Simd Library