UI elements are nil in share extension swift - ios

I've been developing a share extension for my iOS app with a custom view controller. The custom view controller has an ImageView, a label and a textBox. I want to get the url from the webpage where the user tries to share with my app and set it as the text of the label. But when I try to get access to the label, it is nil. I've been trying this operation in diferente lifecycle methods, as viewDidLoad(), viewWillLoad() and finally I use viewDidAppear() but the result it's the same. The elements are properly connected in the storyboard to the Viewcontroller:
Here it's my ViewController code:
import UIKit
import Social
class ShareViewController: UIViewController {
#IBOutlet var ScreenCapture: UIImageView!
#IBOutlet var articleTitle: UITextField!
#IBOutlet var urlLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let item = extensionContext?.inputItems.first as? NSExtensionItem {
if let attachments = item.attachments {
for attachment: NSItemProvider in attachments {
if attachment.hasItemConformingToTypeIdentifier("public.url") {
attachment.loadItem(forTypeIdentifier: "public.url", options: nil, completionHandler: { (url, error) in
if let shareURL = url as? URL {
self.urlLabel.text = shareURL.absoluteString
}
})
}
}
}
}
}
#IBAction func cancelShare(_ sender: Any) {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
#IBAction func doneShare(_ sender: Any) {
//TODO: Insert into CoreData
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
I put a breakpoint in the self.urlLabel.text = shareURL.absoluteStringline and here it's the debugger information:
EDIT: Finally I solved my issue, I must call loadViewIfNeeded():
override func loadViewIfNeeded() {
super.loadViewIfNeeded()
let image = makeScreenShoot(withView: view)
if let item = extensionContext?.inputItems.first as? NSExtensionItem {
if let attachments = item.attachments {
for attachment: NSItemProvider in attachments {
if attachment.hasItemConformingToTypeIdentifier("public.url") {
attachment.loadItem(forTypeIdentifier: "public.url", options: nil, completionHandler: { (url, error) in
if let shareURL = url as? URL {
self.urlLabel.text = shareURL.absoluteString
}
})
}
}
}
}
ScreenCapture.image = image
}

Related

Cannot transfer Data from VC1 to VC2 using protocols in Swift

well, im using 2 VCs, one with a textField where the user inputs the CityName, and another VC where it takes care of all the UI elements(like the temp, cityname, etc..), now I use also a NetWorkManager to take care of all the networking&JSON stuff.
the problem is im trying to transfer the data from the NetWorkManager to VC1 but for some reason the delegate aint working :( - basically the road should be like this : VC2 -> NetWorkManager -> VC1.
Here's my Code:
import Foundation
protocol NetworkManagerDelegate {
func didUpdateWeather(weather: WeatherModel)
}
struct NetworkManager {
let weatherURL = "https://api.openweathermap.org/data/2.5/weather?appid=2da9980c9a43e21c2cdb1f28316d151d&units=metric"
var delegate: NetworkManagerDelegate?
func fetchWeather(cityName: String) {
let urlString = "\(weatherURL)&q=\(cityName)"
performRequest(urlString: urlString)
}
func performRequest(urlString: String) {
if let url = URL(string: urlString) {
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, respone, error) in
if error != nil {
print(error!)
}
if let safeData = data {
if let weather = self.parseJSON(weatherData: safeData) {
print("Im not nil")
self.delegate?.didUpdateWeather(weather: weather)
}
}
}
task.resume()
}
}
func parseJSON(weatherData: Data) -> WeatherModel? {
let decoder = JSONDecoder()
do {
let decodedData = try decoder.decode(WeatherDataModel.self, from: weatherData)
let id = decodedData.weather[0].id
let cityName = decodedData.name
let temp = decodedData.main.temp
let weather = WeatherModel(conditionId: id, cityName: cityName ,temperatrue: temp)
print("Temp is: \(weather.temperatrueString)")
return weather
} catch {
print(error)
return nil
}
}
}
VC2:
import UIKit
import Foundation
class WeatherByCityController: UIViewController, UITextFieldDelegate {
// func didUpdateWeather(weather: WeatherModel) {
// print("Hi")
// }
//
#IBOutlet weak var cityTextField: UITextField!
#IBOutlet weak var updateWeatherBtn: UIButton!
var netWorkManager = NetworkManager()
override func viewDidLoad() {
super.viewDidLoad()
// netWorkManager.delegate = self
cityTextField.delegate = self
}
#IBAction func closeButtonTapped(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
#IBAction func updateWeatherByCityTapped(_ sender: UIButton) {
//Calling delegate to update the City:
//Dismiss the VC:
dismiss(animated: true, completion: nil)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
cityTextField.endEditing(true)
return true
}
func textFieldDidEndEditing(_ textField: UITextField) {
if let city = cityTextField.text {
netWorkManager.fetchWeather(cityName: city)
}
cityTextField.text = ""
}
}
VC1:
import UIKit
import Foundation
import CoreLocation
class WeatherScreen: UIViewController,NetworkManagerDelegate {
//Objects outlets:
#IBOutlet weak var conditionIcon: UIImageView!
#IBOutlet weak var tempLabel: UILabel!
#IBOutlet weak var cityLabel: UILabel!
//TableView Outlet:
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var segeControl: UISegmentedControl!
var models = [DailyWeatherEntry]()
var hourlyModels = [HourlyWeatherEntry]()
var netWorkManager = NetworkManager()
override func viewDidLoad() {
netWorkManager.delegate = self
tableView.register(HourlyTableViewCell.nib(), forCellReuseIdentifier: HourlyTableViewCell.identifier)
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
// Load things once the view will appear
}
#IBAction func locationBtnTapped(_ sender: UIButton) {
//Asking the user for a permission for using his location:
}
func didUpdateWeather(weather: WeatherModel) {
print("Hi")
}
}
extension WeatherScreen: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//creating the cell:
let cell = tableView.dequeueReusableCell(withIdentifier: "weatherCell", for: indexPath) as! HourlyTableViewCell
//Cell Configure:
cell.textLabel!.font = UIFont.systemFont(ofSize: 10)
return cell
}
}
Where is the code for the VC1 ? Without the code for VC 1 it is hard to give an answer. However i'll try to answer as this might be the scenario.
So basically what you are trying to do is make a network call from the VC2 and whatever the response it should be updated in VC1 which is already active somewhere else. Here you just have to set the delegate of the NetworkManger to the VC1 instance. So you have to get the instance of VC1 in VC2.
var netWorkManager = NetworkManager()
//Get this instance in your code
var vc1: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
// Here you will be setting the delegate
// to VC1 where you will be having the delegate methods
netWorkManager.delegate = vc1
cityTextField.delegate = self
}
While this method works I would not recommend using the network manager in such a way. Try to use completion handlers instead of delegates to get the data and then pass that values between the view controllers.
Edited:
Pass completion like this in the Network Manager performRequest function.
func performRequest(urlString: String, completion: #escaping (Bool, String?, Error?) -> Void) {
guard let url = URL(string: urlString) else {
completion(false, nil, NSError(domain: "URLString is not a valid URL", code: 100, userInfo: nil))
return
}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { (data, respone, error) in
guard let safeData = data, let weather = self.parseJSON(weatherData: safeData) else {
print("Empty data or JSON parse error")
completion(false, nil, error)
}
print("Im not nil")
completion(true, weather, nil)
}
task.resume()
}
And call the api request in the VC2.
#IBAction func updateWeatherByCityTapped(_ sender: UIButton) {
//Calling the api request. Pass your url string here
self. netWorkManager.performRequest(urlString: "") { (success, weather, error) in
guard success else {
print(error as Any)
return
}
// Here you have got the weather data.
// Don't know what is weather model. so simply passing the weather string.
self.delegate.didUpdateWeather(weather: weather)
//Dismiss the VC:
dismiss(animated: true, completion: nil)
}
}
Here adopt the NetworkManagerDelegate to VC1 and before presenting the VC2 set the delegate to VC1. Or if you are not presenting the VC2 from VC1 then use UserNotifications to send the weather data to the VC1.
This line of code var netWorkManager = NetworkManager() creates a new instance of network manager each time it is invoked.
In your case, the network manager in VC1 will not get called when the network manager you created in VC2 receives a network response. They are two separate entities.
There a few things you can think about:
If I understand your scenario correctly, your VC2 is used to get a city name from the user. Does VC2 really need to make a network call? You could restrict VC2 to only fetch the city name.
Make the networkManager a singleton. You can then call it from multiple places in your code. The networkManger can have method to 'fetch' and it can take in a completionHandler (as #Raja Vijaya kumar) had suggested.

How can I save an array of images into a firebase database?

I have an app where a user takes some pictures which are saved into an array, then when he presses a button i want the array of images to be saved to firebase. I have searched around and not found any good resources for this. Bellow is the code I have already written.
DataModel where I save the array of images:
import Foundation
import UIKit
class PhotoArray {
static let sharedInstance = PhotoArray()
var photosArray: [UIImage] = []
}
Taking picture code:
import UIKit
import RealmSwift
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// var realm: Realm!
// var photoArray = [PhotoArray]()
#IBOutlet weak var imageView: UIImageView!
let imagePicker = UIImagePickerController()
override func viewDidLoad() {
super.viewDidLoad()
// realm = try! Realm()
imagePicker.delegate = self
imagePicker.sourceType = .camera
imagePicker.allowsEditing = false
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let userPickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
// let imageToUse = PhotoArray()
// let data = UIImagePNGRepresentation(userPickedImage) //here convert to data
PhotoArray.sharedInstance.photosArray.append(userPickedImage) //append converted data in array
// do {
// try realm.write {
// realm.add(imageToUse)
// }
// } catch {
// print(“error adding image to array\(error)“)
// }
imageView.image = userPickedImage
}
// print(PhotoArray().photosArray.count)
imagePicker.dismiss(animated: true, completion: nil)
}
#IBAction func cameraButtonPressed(_ sender: UIButton) {
present(imagePicker, animated: true, completion: nil)
}
#IBAction func cameraButtonPressed(_ sender: UIButton) {
present(imagePicker, animated: true, completion: nil)
}
#IBAction func SendDataPressed(_ sender: UIButton) {
//TODO: Send the Images to Firebase and save it in our database
let messagesDB = Database.database().reference().child("Images")
let messageDictionary = ["Images": PhotoArray.sharedInstance.photosArray as NSArray]
messagesDB.childByAutoId().setValue(messageDictionary) {
(error, refrence) in
if error != nil {
print(error!)
//somthing
}
else {
print("message saved succesfully")
//somthing
}
}
}
}
Firebase databases don't support adding images to the database. You can find the supported Firebase data types here.
You should instead upload your images to a storage provider such as Firebase Cloud Storage and then save the url to that file in your database to download from later.
Here's an example:
//Create a reference to the image
let imageRef = Storage.storage().reference().child("image.jpg")
// Get image data
if let uploadData = UIImagePNGRepresentation(userPickedImage) {
// Upload image to Firebase Cloud Storage
imageRef.putData(uploadData, metadata: nil) { (metadata, error) in
guard error == nil else {
// Handle error
return
}
// Get full image url
imageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
// Handle error
return
}
// Save url to database
Firestore.firestore().collection("images").document("myImage").setData(["imageUrl" : downloadUrl.absoluteString])
}
}
}

Customize FUIAuthPickerViewController

How can I customize the Firebase UI Auth Picker controller with custom buttons, custom actions, background, loader etc..
I already try to subclass the FUIAuthPickerViewController but we can't access to login buttons
This is how you can create your own class of FUIAuthPickerViewController:
Create FUICustomLoginController.swift with:
import UIKit
import FirebaseUI
import FirebaseAuth
class FUICustomLoginController: ViewController {
var authUI: FUIAuth! = FUIAuth.defaultAuthUI()
var auth: Auth = Auth.auth()
private func didSignIn(auth: AuthCredential?, error: Error?, callBack: AuthResultCallback?) {
let callBack: (AuthDataResult?, Error?) -> Void = { [unowned self] result, error in
callBack?(result?.user, error)
self.authUI.delegate?.authUI?(self.authUI, didSignInWith: result, error: error)
}
if let auth = auth {
self.auth.signInAndRetrieveData(with: auth, completion: callBack)
} else if let error = error {
callBack(nil, error)
}
}
func signIn<T: FUIAuthProvider>(type: T.Type, defaultValue: String? = nil) {
try? self.authUI.signOut() // logout from google etc..
self.authUI.providers.first(where: { $0 is T })?.signIn(withDefaultValue: defaultValue, presenting: self, completion: self.didSignIn)
}
}
Subclass your controller from FUICustomLoginController:
class LoginPickerController: FUICustomLoginController {
override func viewDidLoad() {
super.viewDidLoad()
// Customize authUI if needed
//self.authUI.providers = ...
self.authUI.delegate = self
}
#IBAction func loginFacebook(_ sender: Any) {
self.signIn(type: FUIFacebookAuth.self)
}
#IBAction func loginGoogle(_ sender: Any) {
self.signIn(type: FUIGoogleAuth.self)
}
#IBAction func loginPhone(_ sender: Any) {
self.signIn(type: FUIPhoneAuth.self)
}
}
extension LoginPickerController: FUIAuthDelegate {
func authUI(_ authUI: FUIAuth, didSignInWith authDataResult: AuthDataResult?, error: Error?) {
// perform login actions
}
}
You can customize the default buttons, add images etc.. (a working hack )
class SignInViewController: FUIAuthPickerViewController {
weak var delegate: signInProtocol?
// Unhashed nonce.
fileprivate var currentNonce: String?
var backgView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
for each in view.subviews[0].subviews[0].subviews[0].subviews {
if let button = each as? UIButton {
button.layer.cornerRadius = 20.0
button.layer.masksToBounds = true
///do any other button customization here
}
}
///add background image
let scrollView = view.subviews[0]
scrollView.backgroundColor = .clear
let contentView = scrollView.subviews[0]
contentView.backgroundColor = .clear
let background = UIImage(named: "imagename")
let backgroundImageView = UIImageView(image: background)
backgroundImageView.contentMode = .scaleToFill
view.insertSubview(backgroundImageView, at: 0)
}
}

Add elements to search history?

I have a model - Movies.
and two controllers - first for search movie by title, second - for display result with poster, title and year.
Now i need to create some history search on my third controller
(searchHistoryController - TableView) where displayed all movies, and when i tapped on cell with movie's title show movie info.
How I can build it?
I tried create array in my model. And write resutl in it, but each time when i use search it rewrite array, not add new element.
Maybe use realm
Need some help:)
Movie.swift
import Foundation
import UIKit
import Alamofire
import AlamofireImage
protocol MovieDelegate {
func updateMovieInfo()
}
class Movie {
private let omdbUrl = "http://www.omdbapi.com/?"
var title: String?
var filmYear: String?
var poster: String?
var delegete: MovieDelegate!
var historyMovie = [Movie]()
func getMovieInfo(title: String, completion: #escaping ()->()){
let params = ["t": title]
Alamofire.request(omdbUrl, method: .get, parameters: params).validate(statusCode: 200..<300).validate(contentType: ["application/json"]).responseJSON { (response) in
switch response.result {
case .success(let JSON):
let response = JSON as! NSDictionary
let status = response["Response"] as! String
if status == "True" {
self.title = (response["Title"] as! String)
self.filmYear = (response["Year"] as! String)
self.poster = (response["Year"] as! String)
// self.delegete.updateMovieInfo()
completion()
} else {
self.title = (response["Error"] as! String)
completion()
}
case .failure(let error):
print (error)
}
}
}
}
SearchVC
import UIKit
class SearchViewController: UIViewController {
var movie = Movie()
#IBOutlet weak var activityIndicator: UIActivityIndicatorView!
#IBOutlet weak var searchTextField: UITextField!
#IBOutlet weak var searchButton: UIButton!
#IBAction func searchButtonTapped(_ sender: UIButton) {
activityIndicator.startAnimating()
DispatchQueue.main.async {
self.movie.getMovieInfo(title: self.searchTextField.text!, completion: {
self.activityIndicator.stopAnimating()
self.performSegue(withIdentifier: "movieInfo", sender: self)
})
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondVC = segue.destination as! DetailInfoViewController
secondVC.movieTitle = movie.title!
}
}
DetailVC
class DetailInfoViewController: UIViewController, MovieDelegate {
#IBAction func showHistory(_ sender: UIButton) {
performSegue(withIdentifier: "showHistory", sender: self)
}
#IBOutlet weak var posterImageView: UIImageView!
#IBOutlet weak var filmNameLabel: UILabel!
#IBOutlet weak var filmYearLabel: UILabel!
var movie = Movie()
var movieTitle = ""
override func viewDidLoad() {
super.viewDidLoad()
self.movie.getMovieInfo(title: movieTitle ) {
self.updateMovieInfo()
}
self.movie.delegete = self
}
func updateMovieInfo() {
getPoster(link: movie.poster)
filmNameLabel.text = movie.title
filmYearLabel.text = movie.filmYear
}
func getPoster(link: String?) {
if link != nil {
guard let url = URL(string: link!) else { return }
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url) {
DispatchQueue.main.async {
self.posterImageView.image = UIImage(data: data)
}
}
} } else {
self.posterImageView.image = #imageLiteral(resourceName: "Image")
}
}
}
First of all, movieHistory should not be part of your Movie class, but part of your SearchViewController class.
Second of all, unless you want to persist your data, you don't need Realm for this.
Just save the movies in SearchViewController into an array once the search button has been tapped and send it to your other view controller in the segue. Like so
#IBAction func searchButtonTapped(_ sender: UIButton) {
activityIndicator.startAnimating()
DispatchQueue.main.async {
self.movie.getMovieInfo(title: self.searchTextField.text!, completion: {
self.activityIndicator.stopAnimating()
movieHistory.append(movie)
self.performSegue(withIdentifier: "movieInfo", sender: movieHistory)
})
}
}
Also, modify prepare(for segue:...) like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let secondVC = segue.destination as! DetailInfoViewController
secondVC.movieTitle = movie.title!
secondVC.movieHistory = movieHistory
}
In detailVC override prepare(for segue:...) as well and send movieHistory to searchHistoryController the same way it is done in the previous VC.

warning: attempt to present whose view is not in the window hierarchy

I have a UITabView in UIViewController, all tab items are linked to other UIViewControllers. I have written a swift code of downloading a file through internet. when I select second tabItem, this code runs well, it downloads and previews the downloaded file, Then when I click on first tabItem and then again click on second tabItem; file downloads well but it doesn't show any preview instead xCode gives me a warning message:
What I want is download file and preview file both should work when I again click on the second tabItem. whatever the code is.
warning: attempt to present QLPreviewController on KPIViewController whose view is not in the window hierarchy
I have found many solutions on the internet but it didn't work
first solution says to use
let viewer = UIDocumentInteractionController(URL: NSURL(fileURLWithPath: path))
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(viewer, animated: true, completion: nil)
but this function
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(viewer, animated: true, completion: nil)
do not accept
UIDocumentInteractionController
second solution says to override the existing presentViewController function to
override func presentViewController(viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) {
let APP_DELEGATE = UIApplication.sharedApplication().delegate
var presentedModalVC:UIViewController = (APP_DELEGATE!.window?!.rootViewController?.presentedViewController)!
if presentedModalVC == true {
while((presentedModalVC.presentedViewController) != nil){
presentedModalVC = presentedModalVC.presentedViewController!
}
presentedModalVC.presentViewController(viewControllerToPresent, animated: flag, completion: nil)
}
else{
APP_DELEGATE?.window!!.rootViewController?.presentViewController(viewControllerToPresent, animated: flag, completion: nil)
}
}
I tried this but it also needs a UIViewController in its parameters where I have UIDocumentInteractionController
I know these function cannot accept UIDocumentInteractionController type viewController.
here is my whole swift code:
// KPIViewController.swift
// download
//
// Created by me on 15/03/2016.
// Copyright © 2016 me. All rights reserved.
//
import UIKit
class KPIViewController: UIViewController,UITabBarDelegate, NSURLSessionDownloadDelegate, UIDocumentInteractionControllerDelegate{
#IBOutlet weak var tabBar1: UITabBar!
#IBOutlet weak var login_Item: UITabBarItem!
#IBOutlet weak var QAreport_Item: UITabBarItem!
#IBOutlet weak var KpiWebView: UIWebView!
#IBOutlet weak var progressView: UIProgressView!
var downloadTask: NSURLSessionDownloadTask!
var backgroundSession: NSURLSession!
var downloadReport:Bool!
var AuditCodeOfDashboardCell:String?
var AuditCodeForPDF:String?
let isDirectory: ObjCBool = false
override func viewDidLoad() {
super.viewDidLoad()
self.progressView.hidden = true
downloadReport = false
// Do any additional setup after loading the view.
self.tabBar1.delegate = self
}
override func viewDidAppear(animated: Bool) {
self.progressView.hidden = true
downloadReport = false
let backgroundSessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("backgroundSession")
backgroundSession = NSURLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
progressView.setProgress(0.0, animated: false)
var requestURL = NSURL!()
var request = NSURLRequest!()
// loading data from web
if AuditCodeOfDashboardCell != nil{
print(self.AuditCodeOfDashboardCell)
requestURL = NSURL(string:“my URL string&\(AuditCodeOfDashboardCell)”)
request = NSURLRequest(URL: requestURL!)
AuditCodeForPDF = AuditCodeOfDashboardCell
AuditCodeOfDashboardCell = nil
}else{
requestURL = NSURL(string:“my URL string”)
request = NSURLRequest(URL: requestURL!)
}
KpiWebView.loadRequest(request)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem) {
print("selected tabItem: \(item.tag)")
switch (item.tag) {
case 1:
let loginVC = self.storyboard!.instantiateViewControllerWithIdentifier("loginViewController") as! LoginView
presentViewController(loginVC, animated: true, completion: nil)
break
case 2:
if AuditCodeForPDF != nil{
downloadReport = true
let url = NSURL(string: “my URL string&\(AuditCodeForPDF)”)!
urlToDownload = url
}
// if let resultController = storyboard!.instantiateViewControllerWithIdentifier(“2”) as? QAReportViewController {
// presentViewController(resultController, animated: true, completion: nil)
// }
break
default:
break
}
if downloadReport == true{
let url = NSURL(string: “my URL string&\(AuditCodeForPDF)”)!
downloadTask = backgroundSession.downloadTaskWithURL(url)
self.progressView.hidden = false
downloadTask.resume()
downloadReport = false
}
}
// - - Handling download file- - - - - - - - -
func URLSession(session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didFinishDownloadingToURL location: NSURL){
let path = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
let documentDirectoryPath:String = path.first!
let fileManager = NSFileManager()
var destinationURLForFile = NSURL(fileURLWithPath: documentDirectoryPath.stringByAppendingString("/Report.pdf"))
if fileManager.fileExistsAtPath(destinationURLForFile.path!){
// showFileWithPath(destinationURLForFile.path!)
do{
try fileManager.removeItemAtPath(destinationURLForFile.path!)
destinationURLForFile = NSURL(fileURLWithPath: documentDirectoryPath.stringByAppendingString("/Report.pdf"))
}catch{
print(error)
}
}
do {
try fileManager.moveItemAtURL(location, toURL: destinationURLForFile)
// show file
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.showFileWithPath(destinationURLForFile.path!)
})
}catch{
print("An error occurred while moving file to destination url")
}
}
func showFileWithPath(path: String){
let isFileFound:Bool? = NSFileManager.defaultManager().fileExistsAtPath(path)
if isFileFound == true{
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let viewer = UIDocumentInteractionController(URL: NSURL(fileURLWithPath: path))
viewer.delegate = self
viewer.presentPreviewAnimated(true)
})
}
}
func URLSession(session: NSURLSession,
downloadTask: NSURLSessionDownloadTask,
didWriteData bytesWritten: Int64,
totalBytesWritten: Int64,
totalBytesExpectedToWrite: Int64){
progressView.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
}
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController{
return self
}
func documentInteractionControllerDidEndPreview(controller: UIDocumentInteractionController) {
print("document preview ends")
}
}
I cannot find any proper solution that solve my problem. I am new with swift
please anyone on help me. Thanks in advance
UIDocumentInteractionController is not kind of UIViewController. So you cannot present an UIDocumentInteractionController with presentViewController: method.
Checkout https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIDocumentInteractionController_class/
You can presenting a document preview or options menus with UIDocumentInteractionController.

Resources