Depreciated Code from Swift 2 to Swift 3 - xcode

So I followed this tutorial on youtube: https://www.youtube.com/watch?v=uUTevJAhL3Q, and I can't figure out how to update the rest to Swift 3; I am relatively new at Swift and still learning, if anyone could help me out a bit that would be fantastic! I am trying to re-create a snapchat camera-view.
import UIKit
import AVFoundation
class CameraVC: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var captureSession : AVCaptureSession?
var stillImageOutput : AVCaptureStillImageOutput?
var previewLayer : AVCaptureVideoPreviewLayer?
#IBOutlet var cameraView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
previewLayer?.frame = cameraView.bounds
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
captureSession = AVCaptureSession()
captureSession?.sessionPreset = AVCaptureSessionPreset1920x1080
var backCamera = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var error : NSError?
var input = AVCaptureDeviceInput(device: backCamera, error: &error)
if (error == nil && captureSession?.canAddInput(input) != nil){
captureSession?.addInput(input)
stillImageOutput = AVCaptureStillImageOutput()
stillImageOutput?.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
if (captureSession?.canAddOutput(stillImageOutput) != nil){
captureSession?.addOutput(stillImageOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer?.videoGravity = AVLayerVideoGravityResizeAspect
previewLayer?.connection.videoOrientation = AVCaptureVideoOrientation.portrait
cameraView.layer.addSublayer(previewLayer!)
captureSession?.startRunning()
}
}
}
#IBOutlet var tempImageView: UIImageView!
func didPressTakePhoto(){
if let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo){
videoConnection.videoOrientation = AVCaptureVideoOrientation.portrait
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: {
(sampleBuffer, error) in
if sampleBuffer != nil {
var imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(sampleBuffer)
var dataProvider = CGDataProvider(data: imageData as! CFData)
var cgImageRef = CGImage(jpegDataProviderSource: dataProvider, decode: nil, shouldInterpolate: true, intent: kCGRenderingIntentDefault)
var image = UIImage(CGImage: cgImageRef, scale: 1.0, orientation: UIImageOrientation.Right)
self.tempImageView.image = image
self.tempImageView.isHidden = false
}
})
}
}
var didTakePhoto = Bool()
func didPressTakeAnother(){
if didTakePhoto == true{
tempImageView.isHidden = true
didTakePhoto = false
}
else{
captureSession?.startRunning()
didTakePhoto = true
didPressTakePhoto()
}
}
func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
didPressTakeAnother()
}
}

Swift 3 introduced the idea of error handling and most (if not all) of Apple's Foundation and Core APIs got updated so that instead of using capturing an error with the inout &error parameter the method throws and error.
So code that you used to write like this:
var error : NSError?
var input = AVCaptureDeviceInput(device: backCamera, error: &error)
In Swift 3 is updated to drop the error parameter, and you use the new do, try, catch syntax:
do {
var input = try AVCaptureDeviceInput(device: backCamera)
//... input was assigned without an error, you can use in the scope of this statement
}
catch {
// an error occured attempting `AVCaptureDeviceInput(device: backCamera)`
print("an error occured")
}
Of if you prefer, the shorthand versions:
var input = try! AVCaptureDeviceInput(device: backCamera)
// not safe: app will crash if AVCaptureDeviceInput fails
var input = try? AVCaptureDeviceInput(device: backCamera)
// safer: input will be assigned as `nil` if AVCaptureDeviceInput fails
Next time you're converting from Swift 2 to Swift 3, try using Xcode's 'refactor' tool it does a pretty good job of automatically making these changes for you.

Related

Open camera and library only in landscape mode in Swift

I would like to open the camera and library in landscape mode, but I not be able to do it.
Please someone could explain and give me an example.
I have used the below code but seems some code is missing (for instance: import library), I will need a complete example, how I could implement, functions to open library and the camera and save in the camera roll.
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
if let connection = self.previewLayer?.connection {
var currentDevice: UIDevice = UIDevice.currentDevice()
var orientation: UIDeviceOrientation = currentDevice.orientation
var previewLayerConnection : AVCaptureConnection = connection
if (previewLayerConnection.supportsVideoOrientation)
{
switch (orientation)
{
case .Portrait:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
break
case .LandscapeRight:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft
break
case .LandscapeLeft:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.LandscapeRight
break
case .PortraitUpsideDown:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.PortraitUpsideDown
break
default:
previewLayerConnection.videoOrientation = AVCaptureVideoOrientation.Portrait
break
}
}
}
}
Also indicate that I already have some code implemented then
I find it easier to implement without the use of additional libraries like AVFoundation.
I am currently using this code in order to open library and camera.
#IBAction func openLibrary(sender: AnyObject) { ///accion del boton Library
imagePicker.allowsEditing = false
imagePicker.sourceType = .PhotoLibrary
presentViewController(imagePicker, animated:true, completion: nil)
}
#IBAction func openCamera(sender: AnyObject) { ///accion del boton Camara
imagePicker.allowsEditing = false
imagePicker.sourceType = .Camera
presentViewController(imagePicker, animated:true, completion: nil)
}
in ur app delegate use this function:
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int {
if let presentedView = self.window?.rootViewController?.presentedViewController as? CameraViewController {
//cameraView
return Int(UIInterfaceOrientationMask.Landscape.rawValue)
}
} else {
//other view
}
}
Swift 2
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
if let presentedView = self.window?.rootViewController?.presentedViewController as? YourCameraViewController {
//cameraView
return UIInterfaceOrientationMask.Landscape
} else {
//other view
// return here ur orientation for other view
}
}

Background music not working, but no errors?

Please solve my question, why is the background music not working? This is my code, hope someone can solve it.
// Just to format it..
#IBOutlet var UsernameTextField: UITextField!
#IBOutlet var PasswordTextField: UITextField!
#IBOutlet var EmailTextField: UITextField!
#IBAction func LogIn(sender: AnyObject) {
}
func Login(){
var user = PFUser()
user.username = UsernameTextField.text!
user.password = PasswordTextField.text!
PFUser.logInWithUsernameInBackground(UsernameTextField.text, password: PasswordTextField.text, block: {
(User : PFUser?, Error : NSError?) -> Void in
if Error == nil{
dispatch_sync(dispatch_get_main_queue()){
var Storyboard = UIStoryboard(name: "Main", bundle: nil)
var MainVC : UIViewController = Storyboard.instantiateViewControllerWithIdentifier("MainVC") as! UIViewController
self.presentViewController(MainVC, animated: true, completion: nil)
}
}
else{
NSLog("Sorry, you've typed either username or password wrongly.")
}
})
}
#IBAction func signUpButton(sender: AnyObject) {
signUp() // Calling signUp function here that is declared below.
}
func signUp(){
// Do sign up stuff.
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
playBackgroundMusic("IntroMusic")
backgroundMusicPlayer.play()
let soundFilePath = NSBundle.mainBundle().pathForResource("Background", ofType: "mp3")
let soundFileURL = NSURL(fileURLWithPath: soundFilePath!)
let player = AVAudioPlayer(contentsOfURL: soundFileURL, error: nil)
player.numberOfLoops = -1 //infinite
player.play()
func signUp(){
var user = PFUser()
user.username = UsernameTextField.text!
user.password = PasswordTextField.text!
user.email = EmailTextField.text!
}
let user = PFUser()
user.username = "Name:"
user.password = "Pass:"
user.email = "Email:"
user.signUpInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
if error == nil {
// Hooray! Let them use the app now.
} else {
// Examine the error object and inform the user.
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
var backgroundMusicPlayer: AVAudioPlayer!
func playBackgroundMusic(filename: String) {
//The location of the file and its type
let url = NSBundle.mainBundle().URLForResource("Background", withExtension: "mp3")
//Returns an error if it can't find the file name
if (url == nil) {
println("Could not find the file \(filename)")
}
var error: NSError? = nil
//Assigns the actual music to the music player
backgroundMusicPlayer = AVAudioPlayer(contentsOfURL: url, error: &error)
//Error if it failed to create the music player
if backgroundMusicPlayer == nil {
println("Could not create audio player: \(error!)")
return
}
//A negative means it loops forever
backgroundMusicPlayer.numberOfLoops = -1
backgroundMusicPlayer.prepareToPlay()
backgroundMusicPlayer.play()
}
As Leo Dabus suggested declare your player instance outside of viewDidLoad method and your code will be:
var player : AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let soundFilePath = NSBundle.mainBundle().pathForResource("Background", ofType: "mp3")
let soundFileURL = NSURL(fileURLWithPath: soundFilePath!)
player = AVAudioPlayer(contentsOfURL: soundFileURL, error: nil)
player.numberOfLoops = -1 //infinite
player.play()
}

Swift 2 error handling of audio recording code

can someone please assist me? I have some code (which I know runs properly in Xcode 6) that is having difficulty executing in Xcode 7 (due to the changes in error handling for Swift 2). I tried to convert the code using the latest Swift syntax in Xcode 7, but no recommendations were offered. Any suggestions?
//Setup audio session
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayAndRecord,error: nil)
//Initialize and prepare the recorder
audioRecorder = AVAudioRecorder(URL: filePath, settings: nil, error:nil)
audioRecorder.meteringEnabled = true;
audioRecorder.prepareToRecord()
audioRecorder.record()
}
#IBAction func stopAudio(sender: UIButton) {
recordingInProgress.hidden = true
//TODO: Stop recording the user's voice
audioRecorder.stop()
var audioSession = AVAudioSession.sharedInstance();
audioSession.setActive(false, error:nil)
}
The Error messages are for the following code:
session.setCategory(AVAudioSessionCategoryPlayAndRecord,error: nil)
Extra argument 'error' in call
audioRecorder = AVAudioRecorder(URL: filePath, settings: nil, error:nil)
Cannot find an initializer for type 'AVAudioRecorder' that accepts an argument list of type '(URL: NSURL?, settings: nil, error: nil)'
audioSession.setActive(false, error:nil)
****Extra argument 'error' in call****
try this class ive tested this and it works in the latest version of swift and Xcode
import UIKit
import AVFoundation
class RecordViewController: UIViewController {
required init(coder aDecoder: NSCoder) {
var baseString : String = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0] as! String
var pathComponents = [baseString, NSUUID().UUIDString + ".m4a"]
self.audioURL = NSURL.fileURLWithPathComponents(pathComponents)!
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil)
var recordSettings: [NSObject : AnyObject] = Dictionary()
recordSettings[AVFormatIDKey] = kAudioFormatMPEG4AAC
recordSettings[AVSampleRateKey] = 44100.0
recordSettings[AVNumberOfChannelsKey] = 2
self.audioRecorder = AVAudioRecorder(URL: self.audioURL, settings: recordSettings, error: nil)
self.audioRecorder.meteringEnabled = true
self.audioRecorder.prepareToRecord()
// Super init is below
super.init(coder: aDecoder)
}
you will then have to implement your buttons of course
something like this
#IBAction func recordPressed(sender: AnyObject) {
if self.audioRecorder.recording {
self.audioRecorder.stop()
self.recordButton.setTitle("RECORD", forState: UIControlState.Normal)
self.playButton.enabled = true
} else {
var session = AVAudioSession.sharedInstance()
session.setActive(true, error: nil)
self.audioRecorder.record()
self.recordButton.setTitle("PLAY", forState: UIControlState.Normal)
self.playButton.enabled = false
}
}
#IBAction func playPressed(sender: AnyObject) {
self.audioPlayer = AVAudioPlayer(contentsOfURL: self.audioURL, error: nil)
audioPlayer.play()
}
}

How do I setup a sign in page using parse and swift in Xcode (error with 'signInBackgroundWithBlock')?

I'm trying to setup a sign in page using parse and swift in Xcode but I keep getting an error with 'signInBackgroundWithBlock' how do I make this work?
I keep receiving the message
Cannot invoke 'signUpInBackgroundWithBlock' with an argument list of
type ((Bool!, NSError!) -> Void)
so far this is what I have and I just have an error with that part.
import UIKit
import Parse
class EmailLogin: UIViewController, UITextFieldDelegate {
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var statusLabel: UILabel!
#IBOutlet weak var createAccountButton: UIButton!
#IBOutlet weak var passwordTextField: UITextField!
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
emailTextField.delegate = self;
passwordTextField.delegate = self;
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func createAccountButtonPressed(sender: AnyObject)
{
if verifyEmailDomain(self.emailTextField.text)
{
createAccount(self.emailTextField.text, password: self.passwordTextField.text)
}
else
{
//self.statusLabel.text = "Email domain is not valid.";
let alert = UIAlertView()
alert.title = "Invalid Email Domain"
alert.message = "Make sure you entered in your address correctly. If you did, ask your system about using PageMD! Thanks."
alert.addButtonWithTitle("Close")
alert.show()
}
}
func verifyEmailDomain(email: String) -> Bool
{
var isVerifiedDomain = false
let userDomain: String = (email.componentsSeparatedByString("#")).last!
//NSLog(userDomain)
let validDomainsFileLocation = NSBundle.mainBundle().pathForResource("ValidDomains", ofType: "txt")
var validDomainsFileContent = NSString(contentsOfFile: validDomainsFileLocation!, encoding: NSUTF8StringEncoding, error: nil)
//NSLog(validDomainsFileContent!)
let validDomains = validDomainsFileContent!.componentsSeparatedByString("\n")
for domain in validDomains
{
NSLog(domain as! NSString as String)
if userDomain == (domain as! NSString)
{
isVerifiedDomain = true
break
}
}
return isVerifiedDomain
}
func createAccount(email: String, password: String)
{
var newUser = PFUser()
newUser.username = email // We want the user to login only with their email.
newUser.email = email
newUser.password = password
//this where i get my error//
newUser.signUpInBackgroundWithBlock { (succeeded: Bool!, error: NSError!) -> Void in
if error == nil
{
// Account created successfully!
if succeeded == true
{
self.statusLabel.text = "Account created!"
}
}
else
{
if let errorField = error.userInfo
{
self.statusLabel.text = (errorField["error"] as NSString)
}
else
{
// No userInfo dictionary present
// Help from http://stackoverflow.com/questions/25381338/nsobject-anyobject-does-not-have-a-member-named-subscript-error-in-xcode
}
}
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool
{
textField.resignFirstResponder()
return true;
}
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
If you are using swift 1.2 (Xcode 6.3) you need to call the function by:
newUser.signUpInBackgroundWithBlock({(succeeded:Bool, error:NSError?) -> Void in
})
And if you are using swift 1.1 (Xcode 6.1, 6.2) you need to call the function by:
newUser.signUpInBackgroundWithBlock({(succeded:Bool, error:NSError!) -> Void in
})
This is different because of the swift update 1.2 which has changes with using optionals.
Another way is to write it like this:
(Works in old and new swift)
newuser.signUpInBackgroundWithBlock { (succeded, error) -> Void in
}

Using xcode 6 and Swift, how can I grab all objectIds from a class on parse and put them into an array?

I am making a tiny quiz app to help my students study for tests. I have the questions on parse.com and successfully can query objects by their ID one at a time, but I end up having to hard code all the objectIds, and what I would like to do is grab the objectIds, put them into an array, and then pull a random question/objectID from that array as the students click through the questions.
I'm a novice, so ... while I may be able to understand the logic, I'm not sure how to write the code.
Here is the code I'm currently using ... but it doesn't include my failed attempts to put the object IDs in an array. I've been trying to add a function CallIDs() with a parse query to get them all, but so far ... no luck. Any ideas?
import UIKit
import Parse
class ViewController: UIViewController {
var ObjectIDs : [String]!
var Question : String!
var Answers : [String]!
var Answer : String!
#IBOutlet var QuestionLabel: UILabel!
#IBOutlet var Button1: UIButton!
#IBOutlet var Button2: UIButton!
#IBOutlet var Button3: UIButton!
#IBOutlet var Button4: UIButton!
#IBOutlet var AnswerResult: UILabel!
#IBOutlet var Next: UIButton!
#IBOutlet var QuizInstructions: UILabel!
var RandomID = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
Hide()
CallData()
}
func GetRandomObjectID() {
ObjectIDs = ["jr92lfjbQc","r0C8oC4aJ6","XbTTX8xBRf","cjV2z4PSvV","wATbbu0JoX","9Y6HzfeeoD","mNHCMaao41","5qRcqyyXOL","JaLCoeyA1T","nrnifGOP1T","aDAQ6t3saJ","jKF0ZhmPxh"]
RandomID = Int (arc4random_uniform(UInt32(ObjectIDs.count)))
}
func CallData() {
GetRandomObjectID()
var query : PFQuery = PFQuery(className: "QuestionsandAnswers")
query.getObjectInBackgroundWithId(ObjectIDs[RandomID]) {
(ObjectHolder : PFObject!, error : NSError!) -> Void in
if (error == nil) {
self.Question = ObjectHolder ["Question"] as String!
self.Answers = ObjectHolder ["Answers"] as Array!
self.Answer = ObjectHolder ["Answer"] as String!
if (self.Answers.count > 0) {
self.QuestionLabel.text = self.Question
self.Button1.setTitle(self.Answers[0], forState: UIControlState.Normal)
self.Button2.setTitle(self.Answers[1], forState: UIControlState.Normal)
self.Button3.setTitle(self.Answers[2], forState: UIControlState.Normal)
self.Button4.setTitle(self.Answers[3], forState: UIControlState.Normal)
}
} else {
NSLog("Something is wrong, dude. Sorry.")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func Hide() {
AnswerResult.hidden = true
Next.hidden = true
}
func UnHide() {
AnswerResult.hidden = false
Next.hidden = false
}
#IBAction func Button1Action(sender: AnyObject) {
UnHide()
if (Answer == "0") {
AnswerResult.text = "Woot! That's correct!"
} else {
AnswerResult.text = "Nope. Try Again."
}
}
#IBAction func Button2Action(sender: AnyObject) {
UnHide()
if (Answer == "1") {
AnswerResult.text = "Woot! That's correct!"
} else {
AnswerResult.text = "Nope. Try Again."
}
}
#IBAction func Button3Action(sender: AnyObject) {
UnHide()
if (Answer == "2") {
AnswerResult.text = "Woot! That's correct!"
} else {
AnswerResult.text = "Nope. Try Again."
}
}
#IBAction func Button4Action(sender: AnyObject) {
UnHide()
if (Answer == "3") {
AnswerResult.text = "Woot! That's correct!"
} else {
AnswerResult.text = "Nope. Try Again."
}
}
#IBAction func Next(sender: AnyObject) {
CallData()
Hide()
}
}
///// well ... here is the function I attempted to code, but it isn't working:
func CallIDs() {
var query = PFQuery(className: “QuestionsandAnswers”) 
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]!, error: NSError!) -> Void in 
for object in objects {
self.objectIdsArray.append(object.objectId)
  }
}
}
I think the underlying misunderstanding in this question is that objects are to be retrieved using their ids. The requirement is for a random object, and that can be achieved better by knowing only the count of the objects stored on the server.
Getting the count we can select a random object by setting a random skip for a query. So, in the completion block of countObjectsInBackgroundWithBlock, get a random number up to that count like this:
let randomSkip = arc4random_uniform(count)
Now we're ready to do a query with no object id, setting query.skip = randomSkip, and query.limit = 1.
EDIT - If I were to build this in Objective-C, I would do it as follows:
- (void)randomQuestion:(void (^)(NSString *question, NSArray *answers))completion {
PFQuery *countQuery = [PFQuery queryWithClassName:#"QuestionsandAnswers"];
[countQuery countObjectsInBackgroundWithBlock:^(int count, NSError *error) {
NSInteger randomSkip = arc4random_uniform(count);
PFQuery *query = [PFQuery queryWithClassName:#"QuestionsandAnswers"];
query.skip = randomSkip;
query.limit = 1;
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
PFObject *questionAndAnswerObject = objects[0];
NSString *question = questionAndAnswerObject[#"Question"];
NSArray *answers = questionAndAnswerObject[#"Answers"];
completion(question, answers);
} else {
NSLog(#"no error, but no Q&A objects found");
}
} else {
NSLog(#"there was an error %#", error);
completion(nil, nil);
}
}];
}];
}
I am not sure where you declare the array objectIdsArray. I was unable to find it. However the reason you may be having trouble replacing an existing array is because the function you are calling, findObjectsInBackgroundWithBlock does not run on the main thread. The code will continue to execute rather then waiting for the objectIds to download.
In order to make sure that you have downloaded the objectIds first before you try to use them, you may want to use the following code:
func CallIDs() {
var query = PFQuery(className: “QuestionsandAnswers”)
query.selectKeys(["objectId"])
self.objectIdsArray = query.findObjects()
}
Note: When run, you should see the following message:
Warning: A long-running operation is being executed on the main thread.
However I have not yet found this to be a problem. If the download is quick, it should not be noticeable. If it is taking a considerable amount of time, you can add in a UIActivityIndicatorView.

Resources