SpriteKit Swift 2 Trouble writing to plist - plist

hi can somebody point me in the right direction I'm using the latest Xcode and swift I've managed to surtout copying the plist and reading it but it won't write ? any help much appreciated
var NameOfPlist = "Data"
func CopyPlistAndReadContentsToAnArray(NameOfPlist:String)
{
let url = NSURL(string: NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)[0])
let plistPathInDocument = (url?.URLByAppendingPathComponent(NameOfPlist + ".plist").absoluteString)!
if !NSFileManager.defaultManager().fileExistsAtPath(plistPathInDocument)
{
let plistPathInBundle = NSBundle.mainBundle().pathForResource(NameOfPlist, ofType: "plist")!
do
{
try NSFileManager.defaultManager().copyItemAtPath(plistPathInBundle, toPath: plistPathInDocument)
let levelPlist = plistPathInDocument
MainArray = NSMutableArray(contentsOfFile: levelPlist)!
print("plist copied")
}
catch
{
print("error copying plist!")
}
}
else
{
let levelPlist = plistPathInDocument
MainArray = NSMutableArray(contentsOfFile: levelPlist)!
print("PlistInDocOk")
// print("plst \(plistPathInDocument)") // = Data/Application/7D6891BB-2EE5-4D1A-8EB5-73B8100F0827/Documents/Data.plist
// print("This is the MainArray \(MainArray)")
}
}
func SaveToPlist(NameOfPlist:String)
{
let url = NSURL(string: NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)[0])
let plistPathInDocument = (url?.URLByAppendingPathComponent(NameOfPlist).absoluteString)!
MainArray.writeToFile(plistPathInDocument, atomically: true)
print("Item Added")
}

So i woke early this morning And thought I'm going to crack this I put this line in the save plist function
print("plst \(plistPathInDocument)")
which showed me that the .plist was missing
so i added
MainArray.writeToFile(plistPathInDocument + ".plist", atomically: true)
So now its fully working The whole code hope this helps somebody as i had a hard time finding how to do this in Swift 2
variable to hold plist name so you can swap plists easily
var NameOfPlist = "Data"
Function to move plist to docs if its not there and read it
func CopyPlistAndReadContentsToAnArray(NameOfPlist:String)
{
let url = NSURL(string: NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)[0])
let plistPathInDocument = (url?.URLByAppendingPathComponent(NameOfPlist + ".plist").absoluteString)!
if !NSFileManager.defaultManager().fileExistsAtPath(plistPathInDocument)
{
let plistPathInBundle = NSBundle.mainBundle().pathForResource(NameOfPlist, ofType: "plist")!
do
{
try NSFileManager.defaultManager().copyItemAtPath(plistPathInBundle, toPath: plistPathInDocument)
let levelPlist = plistPathInDocument
MainArray = NSMutableArray(contentsOfFile: levelPlist)!
print("plist copied")
}
catch
{
print("error copying plist!")
}
}
else
{
let levelPlist = plistPathInDocument
MainArray = NSMutableArray(contentsOfFile: levelPlist)!
print("Plist In Doc Ok")
print("plst \(plistPathInDocument)") // = Data/Application/7D6891BB-2EE5-4D1A-8EB5-73B8100F0827/Documents/Data.plist
// print("This is the MainArray \(MainArray)")
}
}
function to save to plist
func SaveToPlist(NameOfPlist:String)
{
let url = NSURL(string: NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, .UserDomainMask, true)[0])
let plistPathInDocument = (url?.URLByAppendingPathComponent(NameOfPlist).absoluteString)!
MainArray.writeToFile(plistPathInDocument + ".plist", atomically: true)
print("Item Added")
print("plst \(plistPathInDocument)")
}

Related

How do I load data using ObservableObject in SwiftUI?

I am trying to transition an app from UIKit to SwiftUI which depends on basic DynamoDB resources but I have hit a snag in forcing the view to refresh as data is added to the list. I have been at this set of code for hours trying different things and I thought I might see if anyone might know why the 'SessionsData' seems to be thrown away and will not accumulate the 'Sessions' objects.
Does anyone have any quick thoughts???
class SessionsData: ObservableObject {
let didChange = PassthroughSubject<SessionsData, Never>()
#Published var data: [Sessions] = [] {
didSet {
didChange.send(self)
}
}
init() {
load()
}
func load() {
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
let scanExpression = AWSDynamoDBScanExpression()
scanExpression.limit = 20
var temp : [Sessions] = []
dynamoDBObjectMapper.scan(Sessions.self, expression: scanExpression).continueWith(block: { (task:AWSTask<AWSDynamoDBPaginatedOutput>!) -> Any? in
if let error = task.error as NSError? {
print("The request failed. Error: \(error)")
} else if let paginatedOutput = task.result {
for session in paginatedOutput.items as! [Sessions] {
print("Item Found")
temp.append(session)
}
DispatchQueue.main.async {
self.data = temp
self.didChange.send(self)
}
}
print(self.data.count)
return true
})
}
}
struct Events: View {
#ObservedObject var sessionsData = SessionsData()
var body: some View {...}
}
Looks like you've over-complicated the code. The PassthroughSubject is unnecessary. Whenever you change a #Published property, it should trigger an update.
class SessionsData: ObservableObject {
#Published var data: [Sessions] = []
init() {
load()
}
func load() {
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
let scanExpression = AWSDynamoDBScanExpression()
scanExpression.limit = 20
var temp : [Sessions] = []
dynamoDBObjectMapper.scan(Sessions.self, expression: scanExpression).continueWith(block: { (task:AWSTask<AWSDynamoDBPaginatedOutput>!) -> Any? in
if let error = task.error as NSError? {
print("The request failed. Error: \(error)")
} else if let paginatedOutput = task.result {
for session in paginatedOutput.items as! [Sessions] {
print("Item Found")
temp.append(session)
}
DispatchQueue.main.async {
self.data = temp
}
}
print(self.data.count)
return true
})
}
}
I don't have experience with DynamoDB, but here are a few things from SwiftUI / Combine perspective. In ObseravbleObjects have change a significant bit and and are now declared with objectWillChange and then sending newValue in willSet:
class SessionsData: ObservableObject {
public let objectWillChange = PassthroughSubject<[Sessions], Never>()
public private(set) var items: [Sessions] = [] {
willSet {
objectWillChange.send(newValue)
}
}
init() {
self.items = []
}
public func load() {
let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()
let scanExpression = AWSDynamoDBScanExpression()
scanExpression.limit = 20
var temp: [Sessions] = []
dynamoDBObjectMapper
.scan(Sessions.self,
expression: scanExpression)
.continueWith(block: { (task:AWSTask<AWSDynamoDBPaginatedOutput>!) -> Any? in
if let error = task.error as NSError? {
print("The request failed. Error: \(error)")
} else if let paginatedOutput = task.result,
let sessions = paginatedOutput.items as? [Sessions] {
temp.append(contentsOf: sessions)
}
DispatchQueue.main.async {
self.items = temp
}
}
return true
})
}
}
For the UI part you have to just call your load() method defined above in .onApear() and everything else should happen magically:
struct Events: View {
#ObservedObject var sessionsData: SessionsData
var body: some View {
List {
ForEach(self.sessionsData.items) { session in
Text(session.name) // or something of that kind
}
} .onAppear(perform: { self.sessionsData.load() })
}
}

iOS 13/Swift 5 Encryption/Decryption problem with Commoncrypto

I am using CommonCrypto with AES128/CBC/PKCS7Padding for encryption/decryption.
AES encryption in swift
Referred to the above link, code working fine for below iOS 13 version, but not working for iOS version 13 and above. Please suggest a working solution for iOS 13.Thanks in advance.
func aesDecrypt(key:String, iv:String, options:Int = kCCOptionPKCS7Padding) -> String?
{
if let keyData = key.data(using: String.Encoding.utf8),
let data = NSData(base64Encoded: self, options: .ignoreUnknownCharacters),
let cryptData = NSMutableData(length: Int((data.length)) + kCCBlockSizeAES128)
{
let keyLength = size_t(kCCKeySizeAES128)
let operation: CCOperation = UInt32(kCCDecrypt)
let algoritm: CCAlgorithm = UInt32(kCCAlgorithmAES128)
let options: CCOptions = UInt32(options)
var numBytesEncrypted :size_t = 0
let cryptStatus = CCCrypt(operation,
algoritm,
options,
(keyData as NSData).bytes, keyLength,
iv,
data.bytes, data.length,
cryptData.mutableBytes, cryptData.length,
&numBytesEncrypted)
if UInt32(cryptStatus) == UInt32(kCCSuccess) {
cryptData.length = Int(numBytesEncrypted)
let unencryptedMessage = String(data: cryptData as Data, encoding:String.Encoding.utf8)
print("Decrypt Result unencryptedMessage:::",unencryptedMessage as Any)
return unencryptedMessage
}
else {
print("\(UInt32(cryptStatus))")
return nil
}
}
else {
Logger.log(message: "Faild to decrypt the string", event: .e) // Error
return nil
}
}

video plays in wrong collection view cell

I have a collection view that displays a video in each cell. It also contains a play button and an image which is displayed before the video is played. When I scroll up and down it theres no problem, but when I play a video it shows in the right cell but sometimes it also displays in another cell when I scroll down. I've tried using DispatchQueue(not sure if its the right thing to do) and that doesn't work so I'm stuck for ideas. I have another similar collection view that shows just images and it works perfectly but I'm having issues with this collection view because it displays videos instead. I've searched other questions but I can't find the answer I need to solve this issue. Help would much appreciated. Thanks in advance!
Collection view controller
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: homePostCellId, for: indexPath) as! videoListCollectionViewCell
cell.photoImageView.sd_setImage(with: URL(string: posts[indexPath.item].imageUrl!), placeholderImage: UIImage(named: “placeholder-image.png"))
let tapGesture : UITapGestureRecognizer = UITapGestureRecognizer.init(target: self, action: #selector(playVideo))
return cell
}
}
collection view Cell
class videoListCollectionViewCell: UICollectionViewCell {
var post: videoPost?
lazy var playButton: UIButton = {
let button = UIButton(type: .system)
button.translatesAutoresizingMaskIntoConstraints = false
let image = UIImage(named: "playButton7")
button.tintColor = UIColor.white
button.setImage(image, for: UIControlState())
button.addTarget(self, action: #selector(handlePlay), for: .touchUpInside)
return button
}()
lazy var asset: AVURLAsset = {
let videoUrlString = self.post?.videoUrl
let url = URL(string: videoUrlString!)
var asset: AVURLAsset = AVURLAsset(url: url!)
asset.resourceLoader.setDelegate(self, queue: DispatchQueue.main)
return asset
}()
var playerLayer: AVPlayerLayer?
var player: AVPlayer?
var observer:Any!
func handlePlay() {
// The video has been download already to the document directory
let filename = self.post?.postID
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let filePath = url.appendingPathComponent(filename!)?.path
let fileManager = FileManager.default
let RealURL = NSURL(fileURLWithPath: filePath!)
if fileManager.fileExists(atPath: filePath!) {
player = AVPlayer(url: RealURL as URL)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = photoImageView.bounds
photoImageView.layer.addSublayer(playerLayer!)
player?.play()
playButton.isHidden = true
print("Playing from saved disk")
NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem)
} else {
// The video hasn't been downloaded so it's loading from the URL
if let videoUrlString = post?.videoUrl, let url = URL(string: videoUrlString) {
player = AVPlayer(url: url)
playerLayer = AVPlayerLayer(player: player)
playerLayer?.frame = photoImageView.bounds
photoImageView.layer.addSublayer(playerLayer!)
player?.play()
activityIndicatorView.startAnimating()
playButton.isHidden = true
print("Attempting to play video")
self.observer = self.player?.addPeriodicTimeObserver(forInterval: CMTimeMake(1, 600), queue: DispatchQueue.main) {
[weak self] time in
if self?.player?.currentItem?.status == AVPlayerItemStatus.readyToPlay {
if (self?.player?.currentItem?.isPlaybackLikelyToKeepUp) != nil {
self?.activityIndicatorView.stopAnimating()
}
}
}
NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem)
}
}
}
func playerDidFinishPlaying(note: NSNotification){
print("Video Stopped”)
self.player?.pause()
playButton.isHidden = false
let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality)
let filename = self.post?.postID
let documentsDirectory = FileManager.default.urls(for: FileManager.SearchPathDirectory.documentDirectory, in: FileManager.SearchPathDomainMask.userDomainMask).last!
let archiveURL = documentsDirectory.appendingPathComponent(filename!)
exporter?.outputURL = archiveURL
exporter?.outputFileType = AVFileTypeMPEG4
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
let filePath = url.appendingPathComponent(filename!)?.path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath!) {
} else {
exporter?.exportAsynchronously(completionHandler: {
print(exporter?.status.rawValue)
print(exporter?.error)
})
}
}

Firebase Can Read, But I'm Not Able To Post

App I've created is able to read data from firebase no problem. However, when I try to write data to it, doesn't seem to be working. I checked my rules to make sure ".write" was set to true, still not seeing anything pop up.
Trying to write an event to firebase as follows: ref?.child(email).child("events").setValue("Test")
Email variable has a value, though to double check it wasn't something weird with it I even tried substituting email for "test". Have no idea where else I could be going wrong, any help is a godsend!
Full code for reference:
//
// NewEventToCreateVC.swift
// WSUStudentEvents
//
// Created by Colin Warn on 7/31/17.
// Copyright © 2017 Colin Warn. All rights reserved.
//
import UIKit
import FirebaseDatabase
import Firebase
class NewEventToCreateVC: UIViewController {
var eventToCreate: UserEvent?
#IBOutlet weak var titleOutlet: UILabel!
#IBOutlet weak var startTimeOutlet: UILabel!
#IBOutlet weak var endTimeOutlet: UILabel!
#IBOutlet weak var eventTypeOutlet: UILabel!
#IBOutlet weak var locationOutlet: UILabel!
#IBOutlet weak var descriptionOutlet: UITextView!
#IBOutlet weak var passwordOutlet: UILabel!
let defaults = UserDefaults.standard
var ref: DatabaseReference?
override func viewDidLoad() {
super.viewDidLoad()
ref = DatabaseReference().database.reference()
let formatter = DateFormatter()
formatter.dateStyle = .short
formatter.timeStyle = .short
var startDateString = ""
var endDateString = ""
if let startTime = eventToCreate?.startTime, let endTime = eventToCreate?.endTime {
startDateString = formatter.string(from: startTime)
endDateString = formatter.string(from: endTime)
}
titleOutlet.text = eventToCreate?.eventName
startTimeOutlet.text = startDateString
endTimeOutlet.text = endDateString
eventTypeOutlet.text = eventToCreate?.eventType
locationOutlet.text = eventToCreate?.eventLocation
descriptionOutlet.text = eventToCreate?.description
if let password = eventToCreate?.password {
if password == "" {
passwordOutlet.text = "(no password)"
} else {
passwordOutlet.text = "Password: \(password)"
}
}
// 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) {
print("EVENT TO CREATE, new VC data transfer check")
print(eventToCreate)
print(eventToCreate?.eventName)
}
#IBAction func addEventPressed(_ sender: Any) {
uploadDataToFirebase()
}
#IBAction func backBtnPressed(_ sender: Any) {
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "AddEventViewModelVC") as! AddEventViewModelVC
if let eventName = eventToCreate?.eventName {
nextViewController.eventName = eventName
}
if let eventLocation = eventToCreate?.eventLocation {
nextViewController.eventLocation = eventLocation
}
nextViewController.startTime = eventToCreate?.startTime
nextViewController.endTime = eventToCreate?.endTime
if let description = eventToCreate?.description {
nextViewController.eventDescription = description
}
if let password = eventToCreate?.password {
nextViewController.password = password
}
if let eventType = eventToCreate?.eventType
{
nextViewController.eventType = eventType
}
nextViewController.eventEnum = .password
self.present(nextViewController, animated:true, completion: {
nextViewController.titleLabel.text = nextViewController.eventEnum.rawValue
nextViewController.textField.text = self.eventToCreate?.password
})
}
func uploadDataToFirebase(){
let email = defaults.object(forKey: "email") as! String
print(email)
//Email->Events->Data
//Set Email
//Set events
ref?.child(email).child("events").setValue("Test")
}
}
Thank you so much in advance:
Breaking things down to minimal code can often help in troubleshooting. For example, try this
#class xxxx
var ref: DatabaseReference!
override func viewDidLoad() {
super.viewDidLoad()
ref = Database.database().reference()
ref.child("events").setValue("test")
}
Which will result in a Firebase like this
root_ref
events: "test"
It's also a good idea to include closures in your Firebase calls so you can catch any errors... so instead of setValue, you could use setValue with it's completion block (closure in swift)
let eventsRef = self.ref.child("events")
eventsRef.setValue("test", withCompletionBlock: { error in
if error != nil {
print(error)
}
})

Unable to make Graph + iCloud works

what I have to write here?
db = Graph(cloud: "iCloud.com.devname.appname", completion: { (done, error) in
if let errore = error {
debugPrint("Error iCloud: \(errore.localizedDescription)")
return
}
})
or
db = Graph(cloud: "fantasyString", completion: { (done, error) in
if let errore = error {
debugPrint("Errore iCloud: \(errore.localizedDescription)")
return
}
})
I tried everything but I'm unable to make iCloud works
Thank you for your help, Daniel
EDIT:
the way I read data form db:
var customers : [Entity] {
let search = Search<Entity>(graph: db).for(types: "Customers")
return search.sync(completion: nil).sorted { ($0["name"] as! String) < ($1["name"] as! String)}
}
the way I save the record:
func newCustomer(name:String, phone:String, mail:String, closure: #escaping ()->()) {
let cliente = Entity(type: "Customers")
cliente["name"] = name
cliente["phone"] = phone
cliente["mail"] = mail
db.sync { (done, error) in
if let errore = error {
debugPrint("Errore addCustomer: \(errore.localizedDescription)")
return
}
if done { closure() }
}
}
EDIT 2: the GraphDelegate implementation:
extension DataManager: GraphDelegate {
func graphWillPrepareCloudStorage(graph: Graph, transition: GraphCloudStorageTransition) {
debugPrint("graphWillPrepareCloudStorage")
if transition == .initialImportCompleted {
debugPrint("iCloud initialImportCompleted ok")
self.clientiCont?.tableView.reloadData()
}
}
func graphDidPrepareCloudStorage(graph: Graph) {
debugPrint("graphDidPrepareCloudStorage")
self.clientiCont?.tableView.reloadData()
}
func graphWillUpdateFromCloudStorage(graph: Graph) {
debugPrint("graphWillUpdateFromCloudStorage")
self.clientiCont?.tableView.reloadData()
}
func graphDidUpdateFromCloudStorage(graph: Graph) {
debugPrint("graphDidUpdateFromCloudStorage")
// refresh clienti
self.clientiCont?.tableView.reloadData()
// refresh lista ordini
self.gestCliCont?.tableOrder.reloadData()
// refresh oridine
self.gestOrdCont?.showOrder()
self.gestOrdCont?.tableProdotti.reloadData()
}
}
EDIT: the iCloud config
Thanks to one of my students I found the bug:
if you make a record this way everything works fine:
let record = Entity(type: "Names", graph: self.db)
but if you use this init it doesn't: let record = Entity(type: "Names")
so the solution is: make a record this way
let record = Entity(type: "Names", graph: self.db)

Resources