i have write the follwing code for my function but i failed to execute iterations after delaying.
I want iterations with delay, for example when loop completed execution till i =2 after this when i == 3 this should execute after some delay.
Please guide me to solve this problem.
func allCellsAttempted() -> Bool {
var allCellsAttempted = true
var count = 0
if !oldVersionTriggered {
count = micSources.count
}
else {
count = olderVersionMicSources.count
}
print("Total Mics : \(count)")
for i in 0..<count {
if let cell = micTestFaliureTableView.cellForRow(at: IndexPath(row: i, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
break
}
}
}
return allCellsAttempted
}
You could use a timer. You will need to pass a completion handler closure to your function to access the result.
I would also suggest you access the information from the underlying data model rather than from the table view cells.
func allCellsAttempted(_ completion: #escaping(_ attempted: Bool)-> Void) -> Void {
var allCellsAttempted = true
var count = 0
var target: Int
if !oldVersionTriggered {
target = micSources.count
}
else {
target = olderVersionMicSources.count
}
print("Total Mics : \(target)")
let _ = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] (timer) in
guard let strongSelf = self else {
timer.invalidate()
return
}
if let cell = strongSelf.micTestFaliureTableView.cellForRow(at: IndexPath(row: count, section: 0)) as? MicFaliureTableViewCell {
if !cell.micFaliureTestview.attempted {
allCellsAttempted = false
}
}
count += 1
if count == target || !allCellsAttempted {
timer.invalidate()
completion(allCellsAttempted)
}
}
}
Try to use
DispatchQueue.main.asyncAfter(deadline:.now() + 2.0, execute: { })
Related
This is my enum, which is declared globally in my home view controller (Before class HomeViewController: UIViewController,)
enum HomeVCSectionTypes: String, CaseIterable {
case mostPopularBoolValue = "mostPopularBoolValue"
case discountedBoolValue = "discountedBoolValue"
case newlyAddedBoolValue = "newlyAddedBoolValue"
init?(id : Int) {
switch id {
case 1: self = .mostPopularBoolValue
case 2: self = .discountedBoolValue
case 3: self = .newlyAddedBoolValue
default: return nil
}
}
}
And I am iterating through it in my view will appear like this:
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
for sectionType in HomeVCSectionTypes.allCases {
fetchData(homeVCSectionTypes: sectionType)
}
}
But it is not showing the values according to their serial indexes. What am I missing here?
func fetchData(homeVCSectionTypes: HomeVCSectionTypes) {
self.activityIndicator.startAnimating()
objectArray.removeAll()
let semaphore = DispatchSemaphore(value: 0)
let dispatchQueue = DispatchQueue.global(qos: .background)
dispatchQueue.async {
let docRef = Firestore.firestore().collection("album").order(by: "timestamp", descending: true).whereField(homeVCSectionTypes.rawValue, isEqualTo: true).limit(to: 10)
docRef.getDocuments { (snapshot, error) in
guard let snapshot = snapshot else { return }
var items = [ProductCategoryAlbum]()
if snapshot.documents.count > 0 {
do {
for document in snapshot.documents {
let object = try document.decode(as: ProductCategoryAlbum.self)
items.append(object)
}
self.objectArray.append(HomeObject(sectionName: homeVCSectionTypes.rawValue, sectionObjects: items))
} catch {
print(error)
}
DispatchQueue.main.async {
self.homeTableView.reloadData()
self.activityIndicator.stopAnimating()
}
} else {
DispatchQueue.main.async {
self.homeTableView.isHidden = true
self.noDataLabel.isHidden = false
self.activityIndicator.stopAnimating()
}
}
semaphore.signal()
}
semaphore.wait()
}
}
I am trying to detect the percentage of time that the Main thread is busy so I can log this metric when a user is using the app. Currently, the closest thing I can find is the user_time from basic_info with the help from an answer here but how can i know what thread is being used and if its the main thread? Then from here how can i tell how much of that time as a percentage of the apps total run time for that session?
So i managed to figure this out using the following:
class MainThreadAnalyser {
typealias SumTotal = (total: Double, elements: Double)
private var threadPercentages = [Double]()
private let timeIntervalSeconds: Double
init(timeIntervalSeconds: Double) {
self.timeIntervalSeconds = timeIntervalSeconds
if #available(iOS 10.0, *) {
self.startCPUMonitoring(timeIntervalSeconds: self.timeIntervalSeconds)
}
}
func getAverageCpuUsage() -> Double? {
let sumTotal = threadPercentages.reduce((total: 0, elements: 0)) { (sum, item) -> SumTotal in
var result = sum
if item > 0 {
result.total += item
result.elements += 1
}
return result
}
return sumTotal.elements > 0 ? sumTotal.total / sumTotal.elements : nil
}
#available(iOS 10.0, *)
private func startCPUMonitoring(timeIntervalSeconds: Double) {
Timer.scheduledTimer(withTimeInterval: timeIntervalSeconds, repeats: true) { [weak self] _ in
guard let strongSelf = self else { return }
if let cpuUsage = strongSelf.cpuUsage() {
strongSelf.threadPercentages.append(cpuUsage)
}
}
}
private func cpuUsage() -> Double? {
var kernReturn: kern_return_t
var taskInfoCount: mach_msg_type_number_t
taskInfoCount = mach_msg_type_number_t(TASK_INFO_MAX)
var tinfo = [integer_t](repeating: 0, count: Int(taskInfoCount))
kernReturn = task_info(mach_task_self_, task_flavor_t(TASK_BASIC_INFO), &tinfo, &taskInfoCount)
if kernReturn != KERN_SUCCESS {
return -1
}
var threadArray: thread_act_array_t? = UnsafeMutablePointer(mutating: [thread_act_t]())
var threadCount: mach_msg_type_number_t = 0
defer {
if let threadArray = threadArray {
vm_deallocate(mach_task_self_, vm_address_t(UnsafePointer(threadArray).pointee), vm_size_t(threadCount))
}
}
kernReturn = task_threads(mach_task_self_, &threadArray, &threadCount)
if kernReturn != KERN_SUCCESS {
return -1
}
var totalCPU: Double?
if let threadArray = threadArray {
for index in 0 ..< Int(threadCount) {
var threadInfoCount = mach_msg_type_number_t(THREAD_INFO_MAX)
var thinfo = [integer_t](repeating: 0, count: Int(threadInfoCount))
kernReturn = thread_info(threadArray[index], thread_flavor_t(THREAD_BASIC_INFO),
&thinfo, &threadInfoCount)
if kernReturn != KERN_SUCCESS {
return -1
}
if index == 0 {
let cpuUse = thinfo[4]
totalCPU = Double(cpuUse/10)
}
}
}
return totalCPU
}
}
The main thread is being used constantly while the app is in the foreground.
So you can schedule a timer in applicationDidBecomeActive and invalidate in applicationWillResignActive and get the accumulated seconds whenever you want.
I have declared an optional property of type String. In viewDidload, I call a function which performs optional binding on this property:
public var localMsgIdToBeHighlighted: String? = nil
Following is my method:
private func performInitialBottomScrolling() {
if let safeLocalMsgId = self.localMsgIdToBeHighlighted, let safeMsgList = self.messageList {
var index = 0
var indexPath: IndexPath? = nil
for msgModel in safeMsgList {
if msgModel.localMsgId == safeLocalMsgId {
indexPath = IndexPath(row: index, section: 0)
break
}
index = index + 1
}
if let safeIndexPath = indexPath {
self.tblViewChatLog.scrollToRow(at: safeIndexPath, at: .bottom, animated: false)
if let cell = self.tblViewChatLog.cellForRow(at: safeIndexPath) {
cell.setHighlighted(true, animated: true)
}
} else {
self.scrollToBottom(animation: false)
}
} else {
self.scrollToBottom(animation: false)
}
}
It was working fine but suddenly crashes started occurring in this method:
What can be the reason of this crash?
I am writing an application which tests your ability in Classical Greek. And I have a few View Controllers. In the test view controller, I have a huge Begin button, which when pressed initiates a sequence of code, as follows:
#IBAction func test(_ sender: Any) {
beginBtn.isHidden = true
beginBtn.isEnabled = false
answerOne.isHidden = false
answerTwo.isHidden = false
answerThree.isHidden = false
answerFour.isHidden = false
data.currentNumOQue = (data.qCQ + data.qWQ + data.qSQ)
if data.chooseCAlertDataLoaded == false {
data.chooseCharacterQuestionType.addAction(data.chooseCharacterQuestionTypeEngGrk)
data.chooseCharacterQuestionType.addAction(data.chooseCharacterQuestionTypeGrkEng)
data.chooseCAlertDataLoaded = true
} else {
print("not first question")
}
while data.currentQC <= data.qCQ {
present(data.chooseCharacterQuestionType, animated: false, completion: nil)
DispatchQueue.global(qos: .background).async {
while data.chooseCAlertReturnsEngGrk == nil {
}
DispatchQueue.main.sync {
if data.chooseCAlertReturnsEngGrk == true {
//Eng-Grk QUestion
data.chooseCAlertReturnsEngGrk = nil
} else {
//Grk=Eng QUestion
data.chooseCAlertReturnsEngGrk = nil
}
}
}
data.currentQC += 1
data.currentQ += 1
}
data.currentQC = 1
data.currentQW = 1
data.currentQS = 1
}
Can anyone help me in how to wait until the value chooseCAlertReturnsEngGrk is not nil and execute on, but not 'freezing' the UI when doing so?
Override didSet to call some function.. then in that callback function, do whatever you want with the parameter..
class DataSomething {
var chooseCAlertReturnsEngGrkObserver: ((_ newValue: SomeTime?) -> Void)?
var chooseCAlertReturnsEngGrk: SomeType? = nil {
didSet {
chooseCAlertReturnsEngGrkObserver?(chooseCAlertReturnsEngGrk)
}
}
}
I have a tableViewCell that contains 8 images total divided into two blocks (4 images in each block). These images are downloaded asynchronously and stored into an array and then used in the the tableViewCell's cellForRowAtIndexPath to populate the images. I reload the tableView when all the images for one block has been added to the array in the dictionary (groupTOImages). The way I am doing it, I am getting out of order inconsistent results with the loading of the data. Some images are loaded into places where they shouldn't be. Is there a way to download the images and get consistent results in the tableViewCell.
var groupNames = [NSManagedObject]()
var groupTOPeople = [NSManagedObject: [String]]()
var groupTOImages = [NSManagedObject: [UIImage]]()
func getGroups() {
...
for group in groupNames {
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
print(picUrl)
ImageLoader.sharedLoader.imageForUrl(picUrl) { (image, url) -> () in
self.groupTOImages[group]?.append(image!)
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(UIImage())
mycount++
if mycount == people.count {
self.tableView.reloadData()
}
}
}, failure: nil )
}
}
}
var counter = 0
var groupCount = 0
var groupCounter = 0
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellInfo = GroupCellsArray[indexPath.section]
...
case .userGroups:
let cell = tableView.dequeueReusableCellWithIdentifier(cellInfo.description, forIndexPath: indexPath) as! GroupTableViewCell
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
switch counter {
case 0:
cell.firstTitle.text = (gp.valueForKey("name") as! String)
if let ourImages = groupTOImages[gp] {
for image in ourImages {
print(image.description)
print("groupCount \(groupCounter)")
cell.firstUserButtons[groupCount].layer.borderWidth = 0
cell.firstUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter++
groupCounter++
gp = groupNames[groupCounter]
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
cell.secondUserButtons[groupCount].layer.borderWidth = 0
cell.secondUserButtons[groupCount].setImage(image, forState: .Normal)
groupCount++
if groupCount == ourImages.count {
groupCount = 0
counter = 0
groupCounter++
gp = groupNames[groupCounter]
}
}
}
} else {
cell.secondTitle.text = "Title"
}
default:
break
}
Each row looks like the picture below:
Code using ImageLoader in cellForRowAtIndexPath:
var counter = 0
for group in groupNames {
print("in the second")
groupTOImages[group] = []
if let people = groupTOPeople[group] {
var mycount = 0
for peeps in people {
InstagramEngine.sharedEngine().getUserDetails(peeps, withSuccess: { user in
if let ppic = user.profilePictureURL {
let picUrl = ppic.absoluteString
self.groupTOImages[group]?.append(picUrl)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
} else {
self.groupTOImages[group]?.append(nil)
counter++
mycount++
if counter == self.groupNames.count && mycount == people.count
{
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
}, failure: nil )
}
}
if groupNames.count > 0 {
var gp = groupNames[groupCounter]
print("counter!!!!")
print("groupCount \(counter)")
switch counter {
case 0:
if let ourImages = groupTOImages[gp] {
cell.firstTitle.text = (gp.valueForKey("name") as! String)
print(cell.firstTitle.text)
for image in ourImages {
if let url = image {
print("I get in here")
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.firstUserButtons[self.groupCount].layer.borderWidth = 0
cell.firstUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
case 1:
if let title = gp.valueForKey("name") as? String {
cell.secondTitle.text = title
if let ourImages = groupTOImages[gp] {
for image in ourImages {
if let url = image {
ImageLoader.sharedLoader.imageForUrl(url) { (image, url) -> () in
cell.secondUserButtons[self.groupCount].layer.borderWidth = 0
cell.secondUserButtons[self.groupCount].setImage(image, forState: .Normal)
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter++
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
} else {
self.groupCount++
if self.groupCount == ourImages.count {
self.groupCount = 0
self.counter = 0
self.groupCounter++
gp = self.groupNames[self.groupCounter]
}
}
}
}
} else {
cell.secondTitle.text = "Title"
}
You should replace the self.tableView.reloadData() with
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
Hope this helps!