Create Files,Debug Step By Step,Crash--EXC_BAD_ACCESS - ios

I want to create test.txt file, sample codes.
I run this app, well done.
But when I debug app step by step, it crash, report
(EXC_BAD_ACCESS(code=EXC_l386_GPFLT)),method:
FileManager.default.createFile()
SWIFT CODES:
import UIKit
class ViewController: UIViewController {
#IBAction func CreateFileButton(_ sender: UIButton) {
createFiles()
}
private func createFiles() {
let manager = FileManager.default
let urlForDocument = manager.urls( for: .documentDirectory,
in:.userDomainMask)
let url = urlForDocument[0]
createFile(name:"test.txt", fileBaseUrl: url)
}
func createFile(name:String, fileBaseUrl:URL){
let manager = FileManager.default
let file = fileBaseUrl.appendingPathComponent(name)
print("f: \(file)")
let exist = manager.fileExists(atPath: file.path)
if !exist {
let data = Data(base64Encoded:"aGVsbG8gd29ybGQ=" ,options:.ignoreUnknownCharacters)
let createSuccess = manager.createFile(atPath: file.path,contents:data,attributes:nil)
print("f: \(createSuccess)")
}
}
}
^ Crash step method:FileManager.default.createFile()
^Crash report
^Just run app, do not debug, it well done

Related

Is there a way to pass a ModelEntity to ARQuickLook preview controller?

I'm working on a project where I have to download a USDZ file from a URL, preconfigured with white materials, then customize it in runtime and finally view it in AR with ARQuickLook.
At the moment, I thought the best way was to download the asset using the ModelEntity download method, change its properties and then show it with the ARQuickLook preview.
Currently, I am completely stuck in the last step where I am looking for the way to pass the modified model entity to the ARQuickLook preview controller, but it only accepts a URL and no other data types.
A simple code example below:
var modelURL: URL?
override func viewDidLoad() {
super.viewDidLoad()
self.downloadUSDZ()
}
#IBAction func arQuickLookButtonPressed(_ sender: Any) {
guard modelURL != nil else { return }
let previewController = QLPreviewController()
previewController.dataSource = self
present(previewController, animated: true, completion: nil)
}
func downloadUSDZ() {
modelURL = URL(string: "https://developer.apple.com/augmented-reality/quick-look/models/drummertoy/toy_drummer.usdz")!
guard let entity = try? ModelEntity.loadModel(contentsOf: modelURL!) else {
print("Entity download failed")
return
}
for child in entity.children {
var newMaterial = SimpleMaterial()
newMaterial.color.tint = UIColor.cyan
child.model?.materials = [newMaterial]
}
}
func numberOfPreviewItems(in controller: QLPreviewController) -> Int { return 1 }
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
let previewItem = ARQuickLookPreviewItem(fileAt: modelURL!) //<---- HERE I NEED TO DISPLAY THE MODIFIED MODEL ENTITY
previewItem.canonicalWebPageURL = URL(string: "https://developer.apple.com/augmented-reality/quick-look/models/drummertoy/")
previewItem.allowsContentScaling = false
return previewItem
}
Can anyone give me some advice on how to proceed?
Other ways to reach the goal are also accepted.
I'm not sure if this is doable with ARQuickLook. But we can use either SceneKit or RealityKit ARView and modify the ModelEntity at runtime. You could do something like this, Using ARView in RealityKit:
#IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
let modelURL = URL(string: "https://developer.apple.com/augmented-reality/quick-look/models/drummertoy/toy_drummer.usdz")!
guard let entity = try? ModelEntity.loadModel(contentsOf: modelURL!) else {
print("Entity download failed")
return
}
for child in entity.children {
var newMaterial = SimpleMaterial()
newMaterial.color.tint = UIColor.cyan
child.model?.materials = [newMaterial]
}
let anchor = AnchorEntity(plane: .horizontal)
anchor.addChild(entity)
arView.scene.addAnchor(anchor)
}
Please keep in mind that you will have to manually add the transform/scale actions that you get automatically with ARQuickLook.

UIDocument not working

I'm trying to open document file by following way but nothing happens.
I tried other ways too but it didn't work for me. What is the correct way open Document file (doc,docx,pdf,ppt, etc.). I read somewhere by UIWebView() also this can be done so what is the better way?
let fileURL = URL(fileURLWithPath: documentMessage.fileUrl)
let doc = DocumentPreview(fileURL)
doc.startPreview()
DocumentPreview.swift
class DocumentPreview : NSObject, UIDocumentInteractionControllerDelegate {
var url : URL?
var document : UIDocumentInteractionController?
var previewVC : UINavigationController?
init(_ url: URL) {
super.init()
self.url = url
document = UIDocumentInteractionController(url:url)
document?.delegate = self
}
func startPreview(){
document?.presentPreview(animated:true)
}
func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController {
return previewVC!
}
func documentInteractionControllerDidEndPreview(_ controller: UIDocumentInteractionController) {
print("end Preview")
previewVC!.popViewController(animated: true)
}
}
Take a look at documentMessage. If the .fileUrl property is a URL, then this code is wrong:
let fileURL = URL(fileURLWithPath: documentMessage.fileUrl)
The simplest fix would be this:
let fileURL = documentMessage.fileUrl

How to save the users progress in an array Swift with a plist

Hey guys in my app the user clicks a button called the showfunfact() that moves them through an array of strings. When the user removes the app from multitasking or turns off the phone I want the users place to be saved and then when the reload the can pick up where they left off
var TechfactIndex = 0
let TechnologyfactBook = TechFactBook()
override func viewDidLoad() {
super.viewDidLoad()
let defaults = NSUserDefaults.standardUserDefaults()
TechfactIndex = NSUserDefaults.standardUserDefaults().integerForKey("ByteLocation")
defaults.setObject(TechfactIndex, forKey: "ByteLocation")
}
#IBAction func showFunFact() {
if ( UIApplication.sharedApplication().applicationIconBadgeNumber != 0){
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
}
if (TechfactIndex >= TechnologyfactBook.TechfactsArray.count) {
self.TechfactIndex = 0
}
TechByteLabel.text = TechnologyfactBook.TechfactsArray[TechfactIndex]
TechfactIndex++
}
override func viewDidDisappear(animated: Bool) {
super.viewDidDisappear(animated)
NSUserDefaults.standardUserDefaults().setInteger(TechfactIndex, forKey: "ByteLocation")
NSUserDefaults.standardUserDefaults().synchronize()
}
The thing is that viewDidDisappear: is unrelated to your spec. It is not called "When the user removes the app from multitasking or turns off the phone". It is not called when the phone rings. It is not called when the user hits the home button. It's irrelevant. You've put your code in the wrong place.
What you want to do is register to hear when the app is deactivated. That is the moment to write information into the user defaults.
It's not that expensive of an operation to just write to the User Defaults every time the next fun fact is viewed. So for the sake of simplicity, you could just write the new index to the NSUserDefaults every time they view a new fun fact.
#IBAction func showFunFact() {
if (UIApplication.sharedApplication().applicationIconBadgeNumber != 0){
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
}
TechfactIndex = NSUserDefaults.standardUserDefaults().integerForKey("ByteLocation")
if (TechfactIndex >= TechnologyfactBook.TechfactsArray.count) {
self.TechfactIndex = 0
}
TechByteLabel.text = TechnologyfactBook.TechfactsArray[TechfactIndex]
TechfactIndex++
NSUserDefaults.standardUserDefaults().setInteger(TechfactIndex, forKey: "ByteLocation")
NSUserDefaults.standardUserDefaults().synchronize()
}
However, the user defaults is usually reserved for preferences... so you may be better off implementing a plist (or similar simple saving option) here to store the current index.
EDIT: Here is a simple example on how you could use a plist to achieve this
First, create a Property List file in your directory, call it Data.plist. Make the root object a dictionary and add an NSNumber object with the key FunFactIndex. This will be a template for your plist on the first time a save occurs.
func showFunFact() {
if (UIApplication.sharedApplication().applicationIconBadgeNumber != 0){
UIApplication.sharedApplication().applicationIconBadgeNumber = 0
}
// Load the next index
var factIndex = getCurrentFunFactIndex() as Int
if factIndex < 0 {
println("error")
return
}
if (factIndex >= TechnologyfactBook.TechfactsArray.count) {
factIndex = 0
}
TechByteLabel.text = TechnologyfactBook.TechfactsArray[factIndex]
factIndex++
// Save the index
let saveSuccess = saveFunFactIndex(factIndex);
let successString = (saveSuccess) ? "success" : "failure"
println("Save was a \(successString)")
}
func getCurrentFunFactIndex() -> Int {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as? NSString
let path = documentsDirectory!.stringByAppendingPathComponent("Data.plist")
let fileManager = NSFileManager.defaultManager()
// Check if file exists, copy it over from the bundle if it doesn't
if !fileManager.fileExistsAtPath(path) {
let bundle = NSBundle.mainBundle().pathForResource("Data", ofType: "plist")
fileManager.copyItemAtPath(bundle!, toPath: path, error:nil)
}
if let dataDict = NSDictionary(contentsOfFile: path) {
if let indexNum: AnyObject = dataDict.objectForKey("FunFactIndex") {
return indexNum.integerValue
}
}
return -1 // Something went wrong
}
func saveFunFactIndex(index: Int) -> Bool {
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths.objectAtIndex(0) as! NSString
let path = documentsDirectory.stringByAppendingPathComponent("Data.plist")
let fileManager = NSFileManager.defaultManager()
// Check if file exists, copy it over from the bundle if it doesn't
if !fileManager.fileExistsAtPath(path) {
let bundle = NSBundle.mainBundle().pathForResource("Data", ofType: "plist")
fileManager.copyItemAtPath(bundle!, toPath: path, error:nil)
}
if let dataDict = NSMutableDictionary(contentsOfFile: path) {
let indexNum: NSNumber = index
dataDict.setObject(indexNum, forKey: "FunFactIndex")
return dataDict.writeToFile(path, atomically: true)
}
return false
}
There are two methods I added for you; getCurrentFunFactIndex and saveFunFactIndex:. Both will first check in the Documents directory of the sandbox forData.plist. If that file does not exist, it will copy over the template plist that we created in the bundle. All future uses of these methods will use theData.plist` file that is in the Documents directory. This will allow the value to persist on subsequent app launches (removing the app from the background or turning off the device).

Crosswalks on ios - can not find the XWalkView module

I am trying to use crosswalk to make my web app into iOS app
and I following the steps of Quickstart in this page https://github.com/crosswalk-project/crosswalk-ios
but I keep facing the problem:
in the ViewController.swift
When I import XWalkView, It always appears that It can't find the XWalkView module which makes me stop from my development...
Somebody help me.
Here's the code of ViewController.swift:
import UIKit
import WebKit
import XWalkView
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var start_url = "index.html"
var xwalk_extensions = ["Extension.load"]
if let plistPath = NSBundle.mainBundle().pathForResource("manifest", ofType: "plist") {
if let manifest = NSDictionary(contentsOfFile: plistPath) {
start_url = manifest["start_url"] as? String ?? start_url
xwalk_extensions = manifest["xwalk_extensions"] as? [String] ?? xwalk_extensions
}
}
let webview = WKWebView(frame: view.frame, configuration: WKWebViewConfiguration())
webview.scrollView.bounces = false
view.addSubview(webview)
for name in xwalk_extensions {
if let ext: AnyObject = XWalkExtensionFactory.createExtension(name) {
webview.loadExtension(ext, namespace: name)
}
}
if let root = NSBundle.mainBundle().resourceURL?.URLByAppendingPathComponent("www") {
var error: NSError?
let url = root.URLByAppendingPathComponent(start_url)
if url.checkResourceIsReachableAndReturnError(&error) {
webview.loadFileURL(url, allowingReadAccessToURL: root)
} else {
webview.loadHTMLString(error!.description, baseURL: nil)
}
}
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
perhaps you forget to link the XWalkView.framework in your app target?
Try this step:
Open Xcode, select your app project, in 'General' -> 'Linked Frameworks and Libraries', select '+', choose 'XWalkView.framework' to add it into the linking frameworks. Then shot another build. It's ok if the XWalkView.framework turns red.

Swift -- Audio Recorder/Voice Changer App: How are these functions related?

I have two functions in an audio recorder app I am creating (following a Udacity tutorial.) I am trying to understand how these two functions are related:
#IBAction func recordButton(sender: UIButton) {
recordB.hidden = true
inProgress.hidden = false
stopButtonHide.hidden = false
let dirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as String
let currentDateTime = NSDate()
let formatter = NSDateFormatter()
formatter.dateFormat = "ddMMyyyy-HHmmss"
let recordingName = formatter.stringFromDate(currentDateTime)+".wav"
let pathArray = [dirPath, recordingName]
let filePath = NSURL.fileURLWithPathComponents(pathArray)
println(filePath)
var session = AVAudioSession.sharedInstance()
session.setCategory(AVAudioSessionCategoryPlayAndRecord, error: nil)
audioRecorder = AVAudioRecorder(URL: filePath, settings: nil, error: nil)
audioRecorder.delegate = self
audioRecorder.meteringEnabled = true
audioRecorder.prepareToRecord()
audioRecorder.record()
}
func audioRecorderDidFinishRecording(recorder: AVAudioRecorder!, successfully flag: Bool) {
if(flag) {
recordedAudio = RecordedAudio()
recordedAudio.filePathUrl = recorder.url
recordedAudio.title = recorder.url.lastPathComponent
self.performSegueWithIdentifier("stopRecording", sender: recordedAudio)
} else {
println("Recording was not succesful")
recordB.enabled = true
stopButtonHide.hidden = true
}
}
The first function starts a recording (as I understand it), creates and stores an audio file (names it and gets it a path.) The second function checks to see if the recording is finished. My problem is that I can't see how the two functions connect. How does the second function know to check the recording in the first function? There is a separate class called RecordedAudio.swift that has two variables:
import Foundation
class RecordedAudio: NSObject{
var filePathUrl: NSURL!
var title: String!
}
Why do I need this class? What is the purpose of this class (I know it is the model part of MVC but that's it)? I am trying to understand what is going on in my code as it wasn't that clear to me from the tutorial I am following.
It seems as if recordedAudio is a RecordedAudio object, thus the need for that class.
audioRecorderDidFinishRecording is (as stated in the docs) an AVAudioRecorderDelegate method and is automatically...
called by the system when a recording is stopped or has finished due to reaching its time limit.
In this case, the "recording" would refer to the AVAudioRecorder audioRecorder you've created in recordButton: (and for which you've set its AVAudioRecorderDelegate in order to trigger the audioRecorderDidFinishRecording: method).

Resources