I'm trying to display the user camera (back camera) using the AVFoundation, but I must be doing something wrong because It's only showing a black background image.
I have checked my Privacy > Camera and there isn't any option regarding the camera with my App, and I am not able to display the .Alert action to ask the user the permission to access the camera.
Here is my code, I hope you could help me because this is very weird:
import UIKit
import AVFoundation
class CodigoBarrasViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
#IBOutlet weak var messageLabel:UILabel!
#IBOutlet weak var imagenFondo:UIImageView!
#IBOutlet weak var BackgroundView:UIView!
var string:String!
var captureSession:AVCaptureSession?
var videoPreviewLayer:AVCaptureVideoPreviewLayer?
var qrCodeFrameView:UIView?
// Added to support different barcodes
let supportedBarCodes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeCode128Code, AVMetadataObjectTypeCode39Code, AVMetadataObjectTypeCode93Code, AVMetadataObjectTypeUPCECode, AVMetadataObjectTypePDF417Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypeAztecCode]
override func viewDidAppear(animated: Bool) {
captureSession?.startRunning()
self.qrCodeFrameView?.hidden = true
}
override func viewDidLoad() {
//captureSession?.startRunning()
super.viewDidLoad()
// Get an instance of the AVCaptureDevice class to initialize a device object and provide the video
// as the media type parameter.
let captureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)
do {
input = try AVCaptureDeviceInput(device: captureDevice) as AVCaptureDeviceInput
}
catch let error as NSError {
print(error)
}
// Initialize the captureSession object.
captureSession = AVCaptureSession()
// Set the input device on the capture session.
captureSession?.addInput(input)
//captureSession?.addInput(input as AVCaptureInput)
// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
let captureMetadataOutput = AVCaptureMetadataOutput()
captureSession?.addOutput(captureMetadataOutput)
// Set delegate and use the default dispatch queue to execute the call back
captureMetadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())
captureMetadataOutput.metadataObjectTypes = supportedBarCodes
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer?.frame = view.layer.bounds
view.layer.addSublayer(videoPreviewLayer!)
// Start video capture.
captureSession?.startRunning()
// Move the message label to the top view
view.bringSubviewToFront(imagenFondo)
view.bringSubviewToFront(messageLabel)
view.bringSubviewToFront(BackgroundView)
// Initialize QR Code Frame to highlight the QR code
qrCodeFrameView = UIView()
qrCodeFrameView?.layer.borderColor = UIColor(hex: 0x00B7BB).CGColor
qrCodeFrameView?.layer.borderWidth = 2
view.addSubview(qrCodeFrameView!)
view.bringSubviewToFront(qrCodeFrameView!)
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//self.navigationController?.hidesBarsOnSwipe = true
self.navigationController?.setNavigationBarHidden(true, animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
// Check if the metadataObjects array is not nil and it contains at least one object.
if metadataObjects == nil || metadataObjects.count == 0 {
qrCodeFrameView?.frame = CGRectZero
//messageLabel.text = "No QR code is detected"
return
}
else
{
// Get the metadata object.
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
// Here we use filter method to check if the type of metadataObj is supported
// Instead of hardcoding the AVMetadataObjectTypeQRCode, we check if the type
// can be found in the array of supported bar codes.
if supportedBarCodes.filter({ $0 == metadataObj.type }).count > 0 {
// If the found metadata is equal to the QR code metadata then update the status label's text and set the bounds
let barCodeObject = videoPreviewLayer?.transformedMetadataObjectForMetadataObject(metadataObj as AVMetadataMachineReadableCodeObject) as! AVMetadataMachineReadableCodeObject
qrCodeFrameView?.frame = barCodeObject.bounds
if metadataObj.stringValue != nil {
captureSession?.stopRunning()
self.qrCodeFrameView?.hidden = false
launchApp(metadataObj.stringValue)
}
}
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "seeProduct" {
let destinationController = segue.destinationViewController as! ProductoCamViewController
let string = (sender as! String!)
let backItem = UIBarButtonItem()
backItem.title = " "
navigationItem.backBarButtonItem = backItem
destinationController.ean = string
}
}
func launchApp(decodedURL: String) {
let alertPrompt = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
//let alertPrompt = UIAlertController(title: "", message: decodedURL, preferredStyle: .ActionSheet)
let confirmAction = UIAlertAction(title: "See product", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
self.performSegueWithIdentifier("seeProduct", sender: decodedURL)
})
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Default, handler: { (action) -> Void in
self.captureSession?.startRunning()
self.qrCodeFrameView?.hidden = true
})
//let cancelAction = UIAlertAction(title: "Cancelar", style: UIAlertActionStyle.Cancel, handler: nil)
alertPrompt.addAction(confirmAction)
alertPrompt.addAction(cancelAction)
self.presentViewController(alertPrompt, animated: true, completion: nil)
}
}
Thanks in advance,
Regards.
I would suggest taking a look at UIImagePickerControllerDelegate if you're wanting to access the camera.
Implement this and all of the permission alerts are handled for you
Related
I have made an app that recognize's a piece of art/drawing/paper etc using ARKit. When it recognize's the images it switches to another View Controller and tells you about it. It can recognize one piece of art. The question is how can i have the app recognize multiple drawings. Here is the code.
AR View Controller:
import UIKit
import SpriteKit
import ARKit
import AVFoundation
struct ImageInformation {
let name: String
let description: String
let image: UIImage
}
class ViewController: UIViewController, ARSKViewDelegate {
#IBOutlet var sceneView: ARSKView!
#IBAction func options(){
let alert = UIAlertController(title: "Options", message: "Select one of the options below to continue.", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Enable Flashlight", style: .default, handler: { action in
//Enable Flashlight function
func toggleTorch(on: Bool) {
guard let device = AVCaptureDevice.default(for: AVMediaType.video),
device.hasTorch
else { return }
do {
try device.lockForConfiguration()
device.torchMode = on ? .on : .off
device.unlockForConfiguration()
} catch {
//Torch can not be used.
let alert = UIAlertController(title: "Flashlight Error", message: "We are unable to activate the flashlight. This could be because the flashlight is being used by another app", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dissmis", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .destructive, handler: { action in
fatalError("The flashlight could not be used and user restarted app.")
}))
self.present(alert, animated: true)
}
}
toggleTorch(on: true)
}))
//Continue working on this function when you get back!!!
alert.addAction(UIAlertAction(title: "Disable Flashlight", style: .default, handler: { action in
//Enable flashlight function here
func toggleTorch(off: Bool) {
guard let device = AVCaptureDevice.default(for: AVMediaType.video),
device.hasTorch
else { return }
do {
try device.lockForConfiguration()
device.torchMode = off ? .on : .off
device.unlockForConfiguration()
} catch {
//Torch can not be used.
let alert = UIAlertController(title: "Flashlight Error", message: "We are unable to activate the flashlight. This could be because the flashlight is being used by another app", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dissmis", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .destructive, handler: { action in
fatalError("The flashlight could not be used and user restarted app.")
}))
self.present(alert, animated: true)
}
}
toggleTorch(off: false)
}))
alert.addAction(UIAlertAction(title: "Clear Recently Visited Artworks", style: .destructive, handler: { action in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondViewController = storyboard.instantiateViewController(withIdentifier: "action_done")
self.present(secondViewController, animated: false, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true)
}
var selectedImage : ImageInformation?
let images = ["flower" : ImageInformation(name: "Flower Drawing", description: "This is a drawing of a flower and was made by the developer of this app. It was intended to be a thank you card for a teacher on Teacher appreciation day. The Teacher enjoyed the project.", image: UIImage(named: "flower")!)]
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.showsFPS = false
sceneView.showsNodeCount = false
if let scene = SKScene(fileNamed: "Scene") {
sceneView.presentScene(scene)
}
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
let alert = UIAlertController(title: "Resources not Found", message: "The files needed for this application to work propely can not be found. What would you like to do about this?", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Continue Anyway", style: .default, handler: nil))
alert.addAction(UIAlertAction(title: "Restart App", style: .default, handler: { action in
fatalError("The Recources could not be found on the users device.")
}))
self.present(alert, animated: true)
return
}
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = referenceImages
sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}
// MARK: - ARSKViewDelegate
func view(_ view: ARSKView, nodeFor anchor: ARAnchor) -> SKNode? {
if let imageAnchor = anchor as? ARImageAnchor,
let referenceImageName = imageAnchor.referenceImage.name,
let scannedImage = self.images[referenceImageName] {
self.selectedImage = scannedImage
self.performSegue(withIdentifier: "switch", sender: self)
return imageSeenMarker()
}
return nil
}
private func imageSeenMarker() -> SKLabelNode {
let labelNode = SKLabelNode(text: "✅")
labelNode.horizontalAlignmentMode = .center
labelNode.verticalAlignmentMode = .center
return labelNode
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "switch"{
if let imageInformationVC = segue.destination as? ImageInformationViewController,
let actualSelectedImage = selectedImage {
imageInformationVC.imageInformation = actualSelectedImage
}
}
}
}
Information View Controller:
import Foundation
import UIKit
class ImageInformationViewController : UIViewController {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var descriptionText: UILabel!
var imageInformation : ImageInformation?
override func viewDidLoad() {
super.viewDidLoad()
if let actualImageInformation = imageInformation {
self.nameLabel.text = actualImageInformation.name
self.imageView.image = actualImageInformation.image
self.descriptionText.text = actualImageInformation.description
}
}
#IBAction func dismissView(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
How Can i do this?
Thanks!
The function referenceImages(inGroup:bundle:) loads all reference images from your assets. Just put multiple images into your AR Resource Group in your Assets and assign a unique name for all of them.
I'm having this issue in Xcode 7.3.1. I'm essentially adding a search bar to a map. Here's the first part of the code for context:
import UIKit
import MapKit
class FirstViewController: UIViewController, UISearchBarDelegate {
var searchController:UISearchController!
var annotation:MKAnnotation!
var localSearchRequest:MKLocalSearchRequest!
var localSearch:MKLocalSearch!
var localSearchResponse:MKLocalSearchResponse!
var error:NSError!
var pointAnnotation:MKPointAnnotation!
var pinAnnotationView:MKPinAnnotationView!
#IBAction func showSearchBar(sender: AnyObject) {
searchController = UISearchController(searchResultsController: nil)
searchController.hidesNavigationBarDuringPresentation = false
self.searchController.searchBar.delegate = self
presentViewController(searchController, animated: true, completion: nil)
}
#IBOutlet var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let initialLocation = CLLocation(latitude: 47.6062, longitude: -122.3321)
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
}
centerMapOnLocation(initialLocation)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
Here's the snippet where the error occurs:
func searchBarSearchButtonClicked(searchBar: UISearchBar){
searchBar.resignFirstResponder()
dismissViewControllerAnimated(true, completion: nil)
if self.mapView.annotations.count != 0{
annotation = self.mapView.annotations[0]
self.mapView.removeAnnotation(annotation)
}
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = searchBar.text
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.start{ (localSearchResponse, error) -> Void in
if localSearchResponse == nil{
let alertController = UIAlertController(title: nil, message: "Place Not Found", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.default, handler: nil))
self.present(alertController, animated: true, completion: nil)
return
At localSearch.start, I am getting:
"Value of type MKLocalSearch has no member start"
I'm fairly new to Swift and pretty confused as to what the error is.
I also get:
"expected separator ",""
in the 3rd to last line. But even when changing it, error continues to occur. Could the two be related?
Since you are using older version of swift (swift 2.2) so I think you need to
replace
localSearch.start { ... //this is for swift 3
with
localSearch.startWithCompletionHandler { ... //this is for swift 2.2
For the error , of separator try this:
UIAlertActionStyle.Default
instead of
UIAlertActionStyle.default
Note : I think you also need to change UIAlertControllerStyle.alert to UIAlertControllerStyle.Alert
For some reasons, I can't seem to get my NSUserDefaults to work correctly under Swift 2.0. It work fine under the older version, but under Swift 2.0, it doesn't work. I know the coding has been changed for Swift 2.0, but for some reason, all the information filled in the tableview goes away once I leave that page. Any suggestions?
import UIKit
class MainTableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var name: UITextField!
#IBAction func btnSave() {
let userDefaults = NSUserDefaults.standardUserDefaults()
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
let userDefaults = NSUserDefaults.standardUserDefaults()
NSUserDefaults.standardUserDefaults().setObject(name, forKey:"name")
userDefaults.synchronize()
}
override func viewDidLoad() {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(" ", forKey: "name")
super.viewDidLoad()
}
}
Perhaps try this
import UIKit
class MainTableViewController: UITableViewController, UITextFieldDelegate {
let userDefaults = NSUserDefaults.standardUserDefaults()
#IBOutlet weak var name: UITextField!
#IBAction func btnSave() {
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
} else {
userDefaults.setObject(name.text, forKey:"name")
userDefaults.synchronize()
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
name.text = userDefaults.stringForKey("name")
}
}
In your viewDidLoad you're erasing the info in name, so everytime you enter your view, it will get deleted.
override func viewDidLoad() {
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(" ", forKey: "name")
super.viewDidLoad()
}
Also, since name is a UITextField and not a String, when you're saving your name, it should be done like this:
NSUserDefaults.standardUserDefaults().setObject(name.text, forKey:"name")
instead of this:
NSUserDefaults.standardUserDefaults().setObject(name, forKey:"name")
Also, inside your btnSave() method, you're only saving the name.text if it's equal to "". So if you enter any other information, it won't be saved. I'd recommend modifying it so it looks something like this (you could use guard instead of if name.text also):
#IBAction func btnSave() {
if name.text == "" {
let alert = UIAlertController(title: "Data", message: "Missing Name.", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
return
}
let userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(name.text, forKey:"name")
userDefaults.synchronize()
}
P.S: Remember that NSUserDefaults is intended for user preferences. I'd recommend against saving large amounts of data into NSUserDefaults.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
It was working last night, but when I run my code, now I am receiving a:
fatal error: unexpectedly found nil while unwrapping an Optional value.
Can someone help me locate this error?
import UIKit
class UserRegistration: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate {
//USER REGISTRATION FORM
//Activity Indicator
var activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView()
//Error
func displayAlert(title:String, error:String){
//create Alert
var alert = UIAlertController(title: title, message: error, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Ok", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
//User Profile Picture Selection
var profileImage = UIImage()
var isThereImage = false
#IBOutlet var uploadProfilePictureButton: UIButton!
#IBAction func uploadProfilePicture(sender: AnyObject) {
//Settings needed for image upload
var image = UIImagePickerController()
image.delegate = self
image.sourceType = UIImagePickerControllerSourceType.PhotoLibrary //can use '.camera' to access camera
image.allowsEditing = true
//Select image. FYI Completion is a function that happens when viewcontroller is presented
self.presentViewController(image, animated: true, completion: nil)
}
func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) {
//Store image in local variable to be resized later
profileImage = image
println("Image is selected")
//Manually Close View Controller
self.dismissViewControllerAnimated(true, completion: nil)
//Remove button title
uploadProfilePictureButton.setTitle("", forState: .Normal)
//Display Image
uploadProfilePictureButton.setBackgroundImage(image, forState: .Normal)
//Set isThereImage Boolean
isThereImage = true
}
//---------------------------------------
//User Input Information
#IBOutlet var userEmailAddress: UITextField!
#IBOutlet var userPasswordOne: UITextField!
#IBOutlet var userPasswordTwo: UITextField!
#IBOutlet var passwordConfirmationMatch: UILabel!
var confirmedPassword = Bool()
//---------------------------------------
//Submit User Input to Database
#IBAction func userRegistration(sender: AnyObject) {
var error = ""
//Verify if User Exist and Passwords Match
if userEmailAddress.text == "" || userPasswordOne.text == "" || confirmedPassword == false {
error = "Please enter an email address and password, or make sure your passwords match."
println("Registration had an error")
}
if error != "" {
displayAlert("Error in Registration", error: error)
} else {
//Sign Up User
var user = PFUser()
//Resize Profile Picture
let size = CGSizeApplyAffineTransform(profileImage.size, CGAffineTransformMakeScale(0.5, 0.5))
let hasAlpha = true
let scale: CGFloat = 0.0 // Automatically use scale factor of main screen
UIGraphicsBeginImageContextWithOptions(size, !hasAlpha, scale)
profileImage.drawInRect(CGRect(origin: CGPointZero, size: size))
let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
//User Information
user.password = userPasswordTwo.text
user.email = userEmailAddress.text
user.username = userEmailAddress.text
if isThereImage == false {
displayAlert("Please upload a picture for your profile.", error: error)
}else if isThereImage == true {
var imageData = UIImagePNGRepresentation(scaledImage)
var imageFile = PFFile(name: userEmailAddress.text + ".png", data:imageData)
user.setObject(imageFile, forKey: "userProfileImage")
}
user.setObject("", forKey: "firstName")
user.setObject("", forKey: "lastName")
user.setObject("", forKey: "userLocation")
//Insert Activity Indicator here
activityIndicator = UIActivityIndicatorView(frame: CGRectMake(0, 0, 50, 50))
activityIndicator.center = self.view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.Gray
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.sharedApplication().beginIgnoringInteractionEvents()
//-------------------------------
user.signUpInBackgroundWithBlock {
(succeeded: Bool!, signupError: NSError!) -> Void in
//Stop activity indicator whether there is an error or not
self.activityIndicator.stopAnimating()
UIApplication.sharedApplication().endIgnoringInteractionEvents()
if signupError == nil {
// Hooray! Let them use the app now.
println("Registration Completed")
} else {
//Keep this here!
if let errorString = signupError.userInfo?["error"] as? NSString{
error = errorString
} else {
error = "Please try again later."
}
self.displayAlert("Could not Sign Up", error: error)
println(signupError)
}
}
}
//Print Confirmation to Cortana
}
//---------------------------------------
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
passwordConfirmationMatch.hidden = true
//UITextField Delegate
self.userEmailAddress.delegate = self
self.userPasswordOne.delegate = self
self.userPasswordTwo.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Password Matching Function
func passwordCheck() {
if userPasswordTwo.text == userPasswordOne.text {
passwordConfirmationMatch.hidden = false
confirmedPassword = true
println("Password match")
} else {
passwordConfirmationMatch.hidden = true
confirmedPassword = false
println("Passwords don't match")
}
}
//Handle Keyboard
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
self.view.endEditing(true)
passwordCheck()
}
func textFieldShouldReturn(textField: UITextField!) -> Bool {
userEmailAddress.resignFirstResponder()
userPasswordOne.resignFirstResponder()
userPasswordTwo.resignFirstResponder()
passwordCheck()
return true
}
}
The error you get indicates that one of your variables that has been declared as optional was nil when your code tried to access it.
Do you get any more info from the error? Like the name of the variable for example? If not, use some breakpoints to find the culprit and make sure it is not nil when the time to use it comes.
I am using MWPhotoBrowser for my app. I need to give delete functionality to my users. Is there any way we can implement delete a particular photo or multiple photos functionality?
Quick help needed.
I did this in swift by adding this extension from outside of the library:
extension MWPhotoBrowser {
public override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let _ = valueForKey("_gridController") as? MWGridViewController {
let leftButtonItem = editButtonItem()
//leftButtonItem.tintColor = QorumColors.ThemeWhite
navigationItem.leftBarButtonItem = leftButtonItem
} else {
navigationItem.leftBarButtonItem = nil
}
}
public override func setEditing(editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if editing {
navigationItem.leftBarButtonItem?.title = "Delete"
//navigationItem.leftBarButtonItem?.tintColor = QorumColors.Nickname
displaySelectionButtons = true
title = "Delete Photos"
let gridController = valueForKey("_gridController") as! MWGridViewController
gridController.selectionMode = displaySelectionButtons
gridController.collectionView!.reloadData()
} else {
let nav = self.navigationController as! TempPresentVC
let photosToDelete = nav.selectedPhotos
let afterButtonPress = {
//self.navigationItem.leftBarButtonItem?.tintColor = QorumColors.ThemeWhite
self.displaySelectionButtons = false
self.updateNavigation()
let gridController = self.valueForKey("_gridController") as! MWGridViewController
gridController.selectionMode = self.displaySelectionButtons
gridController.collectionView!.reloadData()
}
guard photosToDelete.count > 0 else {
afterButtonPress()
return
}
let title = "Delete Photo"
let message = "Are you sure you want to delete these photos?"
let action = "Delete"
let cancelAction = "Cancel"
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
let declineButton = UIAlertAction(title: cancelAction, style: .Default, handler: { (action: UIAlertAction) in
afterButtonPress()
})
let acceptButton = UIAlertAction(title: action, style: .Default, handler: { (action: UIAlertAction) in
afterButtonPress()
})
alert.addAction(declineButton)
alert.addAction(acceptButton)
UIApplication.topMostController().presentVC(alert) //private lib
}
}
}
class TempPresentVC: UINavigationController, MWPhotoBrowserDelegate {
var selectedPhotos = [Int]()
func photoBrowser(photoBrowser: MWPhotoBrowser!, photoAtIndex index: UInt, selectedChanged selected: Bool) {
if selected {
selectedPhotos.append(index.toInt)
} else {
selectedPhotos.removeObject(index.toInt)
}
}
}
This doesn't allow you to delete a photo in a single photo view mode, but starting from this code base that part would be easy to implement.
Beware, some of the stuff I use inside are private functions I wrote in my other classes, what they do should be clear though.