index out of range array swift - arrays

i get error index out of range in array
here's my code
.response { request, response, _, error in
self.localPath = destination(NSURL(string: "")!, response!)
self.localPathArray.append(self.localPath!)
}
cell.progressDownload.hidden = false
cell.progressLabel.hidden = false
}
if statusInstantiante == true {
let mainStoryBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc:RedirectMagazineViewController = mainStoryBoard.instantiateViewControllerWithIdentifier("NEXT") as! RedirectMagazineViewController
vc.receiveData = self.localPathArray[indexPath.row] //Error
vc.receiveTitle = titleMagazine[indexPath.item]
self.navigationController?.pushViewController(vc, animated: true)
} else {
print("still downloading")
}
}
I Download pdf file using alamofire download, and get the path (localPath) and append it to localPathArray. the build succeded and can download completely but if i want to view the pdf file it prints index out of range.

Just wrap your line into something like this:
if (self.localPathArray.count > indexPath.row) {
//this condition ensures that your will not request an index that does not exist in the array
vc.receiveData = self.localPathArray[indexPath.row]
}

Related

SceneKit: save scn file to disk

Goal: save scn file to disk.
What I did:
Trying to use this API:
https://developer.apple.com/documentation/scenekit/scnscene/1523577-write
Problem:
Get this error:
AttributeGraph: cycle detected through attribute 248096 ===
The operation couldn’t be completed. (MDLErrorDomain error 0.)
Any help is much appreciated!
let scnScene = SCNScene(named: "Art.scnassets/Ship")!
//get documents URL
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
//save scn to disk
func saveSCNFileToDisk() {
let url = getDocumentsDirectory()
scnScene.write(to: url, options: nil, delegate: nil) { float, error, pointer in
if let error = error {
print(error.localizedDescription)
return
}
self.scene = url.absoluteString
}
}
Your code should specify the file scheme as described in the docs
//save scn to disk
func saveSCNFileToDisk() {
let url = getDocumentsDirectory().appendingPathComponent("someFleName.scn)
scnScene.write(to: url, options: nil, delegate: nil) { float, error, pointer in
if let error = error {
print(error.localizedDescription)
return
}
self.scene = url.absoluteString
}
}

Swift dictionary returns nil after setting key and value pair [duplicate]

This question already has an answer here:
Dictionary with values as array on appending one at a time, remains empty
(1 answer)
Closed 3 years ago.
I'm using a table view controller to section users based off of their occupation. I'm starting off with a dictionary and then converting it into a struct to display the different sections.
The dictionary takes a string and array of user objects:
var userByOccupation: [String: [User]] = [:]
I pull the occupations from the backend (firestore), then the user, then I append the user to the specified occupation. However, whenever I set the value & key, then print out the value count from the dictionary, it's returning nil.
Im getting the error in getUsers() function:
(see the last 3 lines that are also marked with their output)
func getOccupations(){
let db = Firestore.firestore()
db.collection("occupations").getDocuments { (snapshot, err) in
if let error = err {
print("There was an error fetching documents: \(error)")
} else {
guard let documents = snapshot?.documents else { return }
for document in documents {
var occupationID = document.documentID
db.collection("occupations").document(occupationID).collection("users").getDocuments(completion: { (secondSnapshot, error) in
if let err = error {
print("There was an error fetching documents: \(err)")
} else {
guard let secondDocuments = secondSnapshot?.documents else { return }
for document in secondDocuments {
self.getUsers(occupationID: occupationID, userID: document.documentID)
}
}
})
}
}
}
}
func getUsers(occupationID: String, userID: String) {
let db = Firestore.firestore()
db.collection("users").document(userID).getDocument(completion: { (snapshot, error) in
if let err = error {
print("There was an error fetching documents: \(err)")
} else {
if let dictionary = snapshot?.data() {
let user = User(dictionary: dictionary as [String: AnyObject])
user.id = snapshot?.documentID
print(occupationID) //MARK - prints: Janitor
print(user.name) //MARK - prints: Jason
self.userByOccupation[occupationID]?.append(user) //MARK: Setting the key & values
print(self.userByOccupation.keys.count) //MARK - prints: nil.
}
}
})
}
Using ? with self.userByOccupation[occupationID] which is nil at first makes the statement affectless
self.userByOccupation[occupationID]?.append(user)
Change to
self.userByOccupation[occupationID] = [user] // or use +=

Random photos in 12 views – Fatal error: Index out of range

I've got Thread 1: Fatal error: Index out of range looping my 7 photos from array in NSViews.
How to fix it?
let url = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop/ArrayOfElements")
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]).reversed()
let photos = fileURLs.filter { $0.pathExtension == "jpg" }
for index in photos {
let image = [NSImage(data: try Data(contentsOf: index))]
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
view.image = image[i]
}
}
} catch {
print(error)
}
It seems that this line is wrong:
view.image = image[i]
image array has length = 1
Use view.image = image[0] instead
EDIT
let url = URL(fileURLWithPath: NSHomeDirectory()).appendingPathComponent("Desktop/ArrayOfElements")
do {
let fileURLs = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles]).reversed()
let photos = fileURLs.filter { $0.pathExtension == "jpg" }
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
let image = NSImage(data: try Data(contentsOf: photos[i]))
view.image = image
}
} catch {
print(error)
}
Try to create a category to Collection
extension Collection where Index == Int {
/**
Gives a random element of the collection.
- returns: A random element of the collection.
*/
func randomElement() -> Iterator.Element? {
return isEmpty ? nil : self[Int(arc4random_uniform(UInt32(endIndex)))]
}
}
Usage
let numbers = [1,2,3,4,5,6,7,8,9,10]
let randomNumber = numbers.randomElement()
print(randomNumber!)
Edit:
I guess you are making mistake in the following code
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(photos.count-1)))
view.image = image[i]
}
Let's assume photos objects having 10 elements and image object have less than 10 elements, so in such case, you will get this type of error. So change it to the following
for view in arrayOfViews {
let i = Int(arc4random_uniform(UInt32(image.endIndex)))
view.image = image[i]
}

CloudKit nil optional error

I am trying to load, then modify and resave an array.
Here is code, modify func is the top one:
func modifyUserGroupsRequestee(){
print("step2")
acceptedUsersArray.append(groupNameLbl.text!)
//error
userGroupRecordToUpdate.setObject(acceptedUsersArray as CKRecordValue?, forKey: "userGroups")
database.save(recordToUpdate) { (savedRecord, error) in
if error != nil{
print(error.debugDescription)
}else{
print("SAVED RECORD")
}
}
}
func resaveUserGroups(){
print(addedUser)
print("step1")
// add group to requestees user groups
let pred = NSPredicate(format: "username = %#", "\(addedUser)")
let query = CKQuery(recordType: "PersonalUser", predicate: pred)
let operation = CKQueryOperation(query: query)
//operation.resultsLimit = CKQueryOperationMaximumResults
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil{
self.userGroupRecordToUpdate = record
// self.acceptedUsersArray = (record.object(forKey: "userGroups") as! Array)
print("usergroup names:: \(self.acceptedUsersArray)")
if let acceptedUserArrays = record.object(forKey: "userGroups") as? [String] {
// self.feedTableView.reloadData()
self.acceptedUsersArray = acceptedUserArrays
print("looks like we r going forward")
self.modifyUserGroupsRequestee()
// }
//self.feedTableView.reloadData()
print(groupNames.count)
print(self.acceptedUsersArray)
}
}
database.add(operation)
//self.tableView.reloadData()
// print(leaderboardInfo.count)
}
}
The function prints step1 but never gets to step2. In the bottom function, I have an if let statement I tried to create to solve my nil issue (I commented my previous code above that line- self.acceptedUsersArray... Anyway, I believe I am implementing the if let statement incorrectly, because no data is loaded, even though there is data in cloud kit.
And I do have my personal user cloudKit records set up, here's a pic:
You should try to keep your code always indented consistently.
(In Xcode editor, Cmd+A (Select All), then Ctrl+I (Re-Indent).)
With confusing comments removed, your resaveUserGroups shows as:
func resaveUserGroups() {
print(addedUser)
print("step1")
// add group to requestees user groups
let pred = NSPredicate(format: "username = %#", "\(addedUser)")
let query = CKQuery(recordType: "PersonalUser", predicate: pred)
let operation = CKQueryOperation(query: query)
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
self.userGroupRecordToUpdate = record
print("usergroup names:: \(self.acceptedUsersArray)")
if let acceptedUserArrays = record.object(forKey: "userGroups") as? [String] {
self.acceptedUsersArray = acceptedUserArrays
print("looks like we r going forward")
self.modifyUserGroupsRequestee()
print(groupNames.count)
print(self.acceptedUsersArray)
}
}
database.add(operation)
}
}
Omitting some parts to clarify:
func resaveUserGroups() {
//...
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
//...
}
database.add(operation)
}
}
The line database.add(operation) exists inside the recordFetchedBlock.
You may need to fix some more parts (that's another story), but at least, you need to move the line out of the closure to execute the operation you have created:
func resaveUserGroups() {
//...
operation.recordFetchedBlock = { (record: CKRecord!) in
if record != nil {
//...
}
//database.add(operation)
} //↓
database.add(operation)
}
I just solved it. Apparently there always needs to be some kind of value inside the array even if it was just created. I was trying to query an array that existed in the recordType, but not yet under the specific record.

swift iterating webfolder for putting filenames in a array

I want to put the filenames of a web folder "mywwwaddress" into an array
but the println gives me an empty array: []
func files(){
var urls : [NSURL] = []
let dirUrl = NSURL(string: "mywwwadres")
let fileManager = NSFileManager.defaultManager()
let enumerator:NSDirectoryEnumerator? = fileManager.enumeratorAtURL(dirUrl!, includingPropertiesForKeys: nil, options: nil, errorHandler: nil)
while let url = enumerator?.nextObject() as! NSURL? {
urls.append(url)
}
println(urls)
}
When I try your code with a URL of a directory on my local file system, it works OK for me, so you may want to put more error handling in to see if there's a problem reaching the URL you're using.
Also, since NSEnumerator conforms to SequenceType, you can use for...in or other sequence-processing operations like map on it instead, which can simplify the code a little.
Here's a version with more error handling to try:
func files() {
let fileManager = NSFileManager.defaultManager()
let url = NSURL(string: "mywwwadres")
assert(url != nil, "Invalid URL")
let enumerator = url.flatMap { fileManager.enumeratorAtURL($0,
includingPropertiesForKeys: nil,
options: nil)
{ url, error in
println("error with url \(url): \(error)")
return true // true to keep going
}
}
assert(enumerator != nil, "Failed to create enumerator")
let urls = enumerator.map { enumerator in
map(enumerator) { url in
url as! NSURL
}
}
println(urls ?? [])
}

Resources