Post

Replies

Boosts

Views

Activity

Swift - Async calls in loop
Hi guys, I hope you are doing fine. I am trying to achieve following thing: ) Fetch data array from database (async call) ) Iterate over fetched data array ) Fetch additional information about each object (async call) ) Create a new data array with all the information and return it back Currently, I have following approach self.dataAccessService.fetchRepliesByCommentId(completionHandler: { (commentReplyArray) in       for var i in 0..<commentReplyArray.count {         let commentReply = commentReplyArray[i]         let commentItem = CommentItem()                   self.fetchDetailsAboutCommentReply(commentReplyObject: commentReply) { (commentItem) in           commentItem.commentObject = commentReply                       dataSource.insert(commentItem, at: index + i + 1) -> APP CRASHES HERE, i is never 0 here           ips.append(IndexPath(row: index + i + 1 , section: 0))                                                                      if (i == commentReplyArray.count - 1) {             self.delegate?.didLoadReplies(dataSource: dataSource, ips: ips)           }         }       }     }, commentId: commentItem.commentObject.id) My fetchDetailsAboutCommentReply function: private func fetchDetailsAboutCommentReply(commentReplyObject:CommentReply, completionHandler:@escaping(CommentItem)->()) {      let group = DispatchGroup()      let commentItem = CommentItem()            group.enter()       self.dataAccessService.fetchUserById(completionHandler: { (userObject) in         commentItem.userObject = userObject         group.leave()      }, uid: commentReplyObject.userId)                   group.enter()       self.dataAccessService.fetchDownloadURLOfProfileImage(organizerId: commentReplyObject.userId) { (contentURL) in       commentItem.userObject.contentURL = contentURL       group.leave()      }           group.notify(queue: .main) {       completionHandler(commentItem)     }   } My question is how, I can change my code, so the loop basically "pauses" until I fetch every detail information of the iterated object, add it into the dataSource Array and then continues with the next one? Thanks and stay healthy!
11
0
5.1k
Dec ’20
Swift - Firestore - Large video upload fails
So the use case I want to do is easy. ) Select a video from library ) Trim video and apply a CIFilter  ) Upload it to FireStore Here is my code: ) Select a video from library func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {     var image = UIImage()            let applyEffectController = STORYBOARD.instantiateViewController(withIdentifier: "applyEffects") as! ApplyEffectsViewController                 if let mediaType = info[UIImagePickerController.InfoKey.mediaType] as? String {       if mediaType == "public.image" {         let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage         image = pickedImage!       }                    if mediaType == "public.movie" {              let videoURL = info[.mediaURL] as! URL         image = AVUtil.createThumbnail(videoURL: videoURL)                   let avAsset = AVUtil.trimVideo(videoURL: videoURL)         let fileManager = FileManager.default         let documents = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)                   try! avAsset.export(to: documents.appendingPathComponent(VIDEO_NAME))                   applyEffectController.avAsset = avAsset         applyEffectController.IS_VIDEO_SELECTED = true       }     }     self.dismiss(animated: true, completion: nil)                applyEffectController.challengeImage = image     self.navigationController?.pushViewController(applyEffectController, animated: true)   } ) Trim video and apply a CIFilter  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {     var chosenFilter = filterImagesArray[indexPath.row]     chosenFilter = stripFileExtension(chosenFilter)           let contentFilter = CIFilter(name: chosenFilter)     let challengeCIImage = CIImage(image: challengeImage)               contentFilter!.setValue(challengeCIImage, forKey: kCIInputImageKey)     let editedChallengeImage = contentFilter!.value(forKey: kCIOutputImageKey) as! CIImage     challengeImageView.image = UIImage(ciImage: editedChallengeImage)          if (IS_VIDEO_SELECTED) {       playerItem?.videoComposition = AVVideoComposition(asset: avAsset!, applyingCIFiltersWithHandler: { (request) in         let source = request.sourceImage.clampedToExtent()         contentFilter?.setValue(source, forKey: kCIInputImageKey)                   _ = CMTimeGetSeconds(request.compositionTime)                   let output = contentFilter?.outputImage!.cropped(to: request.sourceImage.extent)                   request.finish(with: output!, context: nil)       })     }   } Confirm filter and redirect to the view controller where I do the upload @objc func confirmButton_clicked() {     let createChallengeController = STORYBOARD.instantiateViewController(withIdentifier: "createChallenge") as! CreateChallengeViewController     createChallengeController.IS_VIDEO_SELECTED = IS_VIDEO_SELECTED     createChallengeController.challengeImage = challengeImageView.image!     createChallengeController.challengeObject = challengeObject               if (IS_VIDEO_SELECTED) {       let fileManager = FileManager.default       let documents = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)               if (fileManager.fileExists(atPath: documents.appendingPathComponent(EDITED_VIDEO_NAME).path)) {         DispatchQueue.main.async(execute: {           try! fileManager.removeItem(atPath: documents.appendingPathComponent(EDITED_VIDEO_NAME).path)         })       }               let videoExport = AVAssetExportSession(asset: (playerItem?.asset)!, presetName: AVAssetExportPresetMediumQuality)       videoExport?.outputFileType = .mov       videoExport?.outputURL = documents.appendingPathComponent(EDITED_VIDEO_NAME)       videoExport?.videoComposition = playerItem?.videoComposition       createChallengeController.challengeImage = self.challengeImageView.image!       print(videoExport?.outputURL)               let group = DispatchGroup()       group.enter()       self.view.addSubview(activityView)               videoExport?.exportAsynchronously(completionHandler: {         createChallengeController.videoURL = videoExport?.outputURL         group.leave()       })               group.notify(queue: .main) {         self.navigationController?.pushViewController(createChallengeController, animated: true)         self.activityView.removeFromSuperview()       }     }     else {       self.navigationController?.pushViewController(createChallengeController, animated: true)     }   } *3.) Upload it to FireStore var videoData = NSData() &#9;&#9;do { &#9;&#9;&#9;&#9;videoData = try NSData(contentsOf: self.videoURL!, options: .dataReadingMapped) &#9;&#9;} &#9;&#9;catch { &#9;&#9;&#9;&#9;cancelChallenge(challengeId: challengeId) // always goes here -> it fails &#9;&#9;&#9;&#9;return &#9;&#9;} The exception I get is: "The file “editedVideo.mov” couldn’t be opened because there is no such file." The approach above works with videos which are about 30-35 sec. (without trmming). If I upload a video which is about two minutes, then it always fails. I need your help. Thank you and stay healthy! *
5
0
1.2k
Nov ’20
Swift - UITableView - Dynamic height of cells
Hello everyone, I have been struggling a lot with this issue: Using an UITableView, I want to use a custom UITableViewCell which contains labels and an image view. Depending on how long the text is, which I want to display on the labels, the height of the cell should be adjusted automatically. Currently, I have this approach in my viewDidLoad method:   activityTableView.translatesAutoresizingMaskIntoConstraints = false     self.view.addSubview(activityTableView)     activityTableView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true     activityTableView.widthAnchor.constraint(equalToConstant: width).isActive = true     activityTableView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: height * (60 / IPHONE8_SCREEN_HEIGHT)).isActive = true     activityTableView.heightAnchor.constraint(equalToConstant: height * (554 / IPHONE8_SCREEN_HEIGHT)).isActive = true     //activityTableView.frame = CGRect(x: 0, y: navigationBar.frame.maxY, width: width, height: height * (554 / IPHONE8_SCREEN_HEIGHT))     activityTableView.delegate = self     activityTableView.dataSource = self     activityTableView.register(ActivityTableViewCell.self, forCellReuseIdentifier: "activityCell")       activityTableView.estimatedRowHeight = 92     activityTableView.rowHeight = UITableView.automaticDimension       Furthermore, I have delegates: extension ActivityViewController:UITableViewDelegate {   func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {     return UITableView.automaticDimension   }   } My custom table view cell func initActivityLabel() {     activityLabel.translatesAutoresizingMaskIntoConstraints = false     self.contentView.addSubview(activityLabel)     activityLabel.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 81).isActive = true     activityLabel.widthAnchor.constraint(equalToConstant: cellWidth * (276 / cellWidth)).isActive = true     activityLabel.topAnchor.constraint(greaterThanOrEqualTo: self.contentView.topAnchor, constant: 13).isActive = true     activityLabel.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -38).isActive = true           activityLabel.setColorForLabelTitle()     activityLabel.font = .boldSystemFont(ofSize: LABEL_TEXT_SIZE)     activityLabel.numberOfLines = 0     activityLabel.lineBreakMode = .byWordWrapping     activityLabel.sizeToFit()   }       func initActivityButton() {     self.activityButton.translatesAutoresizingMaskIntoConstraints = false     self.contentView.addSubview(activityButton)           activityButton.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 250).isActive = true     activityButton.widthAnchor.constraint(equalToConstant: 131).isActive = true     activityButton.topAnchor.constraint(equalTo:self.activityLabel.bottomAnchor, constant: 0).isActive = true     activityButton.heightAnchor.constraint(equalToConstant: 40).isActive = true         activityButton.addTarget(self, action: #selector(activityButton_clicked), for: .touchDown)     activityButton.setColor()     activityButton.roundCorners()     self.layoutIfNeeded()   } Those init-functions are called within this method func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {     let activityCell = tableView.dequeueReusableCell(withIdentifier: "activityCell", for: indexPath) as! ActivityTableViewCell     activityCell.selectionStyle = .none     activityCell.sizeToFit()         activityCell.backgroundColor = DARK_BLUE_COLOR     let activityObject = activityArray[indexPath.row]       &#9;&#9; activityCell.initActivityLabel() .. &#9;&#9; As you can see, everything is done programmatically. I need to do it like this, so I was wondering if you could give me any hints. When I run the code, the table view doesn't show the label at all. I get a warning regarding a constraint violation. But why?
0
0
2.3k
Jul ’20
UITableView - Design for comments and replies
Hello everyone, I am currently working on having an application to display comments with respective replies. I can show all the comments easily in a table view having a simple array of comment objects. In case, one of the comment has any replies (in the database stored), I need to load those replies - which are represented as a different objects at the moment - and display them under the correct comment. For the table view, this means, new rows are going to be inserted. I tried to code this but somehow, this ends up in an endless loop. Maybe you guys can give me a hint? This is my function to load the comments first func fetchCommentsByParticipationId() {     dataAccessService.fetchCommentsByParticipationId(completionHandler: { (commentArray) in       self.commentArray = commentArray       self.commentTableView.reloadData()     }, participationId: participationObject.id)   } I have two arrays as data sources. One contains the comments and the other ones contains the comment replies  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {     return commentArray.count + commentReplyArray.count   } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {     let commentsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CommentsTableViewCell") as! CommentsTableViewCell     commentsTableViewCell.backgroundColor = DARK_BLUE_COLOR           let cellHeight = commentsTableViewCell.frame.height     let cellWidth = commentsTableViewCell.frame.width           let commentObject = commentArray[indexPath.row] // Comment(json: (hitsTableController.hitsSource?.hit(atIndex: indexPath.row))!)           commentsTableViewCell.initSenderLabel(cellWidth: cellWidth, cellHeight: cellHeight)     commentsTableViewCell.initReplyButton(cellWidth: cellWidth, cellHeight: cellHeight)     dataAccessService.fetchUserById(completionHandler: { (userObject) in       commentsTableViewCell.senderLabel.text = userObject.firstName + " " + userObject.lastName     }, uid: commentObject.userId)           commentsTableViewCell.initCommentLabel(cellWidth: cellWidth, cellHeight: cellHeight)     commentsTableViewCell.commentTextView.text = commentObject.comment           commentsTableViewCell.replyButtonAction = { [unowned self] in       self.commentReplyObject.commentId = commentObject.id       self.commentReplyObject.userId = commentObject.userId       var replyToUserName = commentsTableViewCell.senderLabel.text!       replyToUserName = replyToUserName.replacingOccurrences(of: " ", with: "")               self.replyToUser(replyToUserName: replyToUserName)     }           // fetch replies to comments     dataAccessService.fetchRepliesByCommentId(completionHandler: { (_commentReplyArray) in       for commentReply in _commentReplyArray {         self.commentReplyArray.append(commentReply)         self.commentTableView.insertRows(at: [           (NSIndexPath(row: self.commentArray.count-1, section: 0) as IndexPath)], with: .bottom)         commentsTableViewCell.initReplyViews(cellWidth: cellWidth, cellHeight: cellHeight)                   commentsTableViewCell.senderLabel.text = "Test"         commentsTableViewCell.commentTextView.text = commentReply.comment       }     }, commentId: commentObject.id)     return commentsTableViewCell   } ``` What would be the best idea to achieve what I want to do?
1
0
1.3k
Jul ’20
OneSignal - Swift - Receiving push notification in different languages
I am using the sdk from OneSignal. Let's assume, I have following use case:User A use my app in German language. He triggers an action within the app e. g. a like on an image of User B. User B gets a push notification about the like. But User B uses the app in English language. How can I achieve that?I mean, I can send the notification message in a particular language but if User B decides to change the language of the mobile device to Turkish, then I have to be flexibel.Is there any way, I can access the incoming push notification on the target device?Currently, my code for sending the notification from the source device looks like this:public func notifyAboutSubscription(userObject:User, receiverArray:[String]) { var receiverArray = removeChallengeCreatorTokenFromArray(receiverArray: receiverArray) notificationTypeService.clearReceiverListForNotificationType(completionHandler: { (clearedReceiverArray) in receiverArray = clearedReceiverArray let source = self.determineUserType(userObject: userObject) OneSignal.postNotification(["contents": ["en": source + NSLocalizedString(FOLLOW_MESSAGE, comment: "")], "include_player_ids": receiverArray]) }, receiverList: receiverArray, notificationType: NotificationType.follow) }I am thankful for any hintsBest regards,Nazar Medeiros
2
0
1.4k
Jun ’20
Issue with auto layout
Hello everyone,I am working with auto layouts for the first time, but I am a but confused. Let me explain you my problem by showing the code I havefunc setupView() { self.view.translatesAutoresizingMaskIntoConstraints = false var createdButton = UIButton() createdButton.setTitle(CREATED_BUTTON_TITLE, for: .normal) createdButton.setTitleColor(DARK_BLUE_COLOR, for: .normal) createdButton.backgroundColor = UIColor.white createdButton.addTarget(self, action: #selector(fetchMyChallenges), for: .touchDown) createdButton.layer.borderWidth = 1.5 createdButton.layer.borderColor = UIColor.white.cgColor self.view.addSubview(createdButton) createdButton.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true createdButton.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: self.view.frame.width / 3).isActive = true createdButton.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 60).isActive = true createdButton.heightAnchor.constraint(equalTo: self.view.heightAnchor, constant: 54).isActive = true ...So basically, I just want to show a button with some properties set on my view controller. The button appears correctly with the code above, however, the view (self.view) itself is black. I expect it to be black.My questions:1.) Do I always have to set translatesAutoresizingMaskIntoConstraints for super views? Like in this case for self.view?2.) What is actually the correct way of solving it? Is my approach correct? If yes, how I do avoid that black background color?Best regards,Nazar Medeiros
8
0
1.2k
Mar ’20