Post

Replies

Boosts

Views

Activity

How to properly implement delay gap between operations for NSOperationQueue?
I have the following method in NSOperationQueue category:- (void)addOperation:(NSOperation *)op withDelayInNanoseconds:(int64_t)nanoseconds { int64_t delay = (self.operationCount * nanoseconds); int64_t timeInterval = (int64_t)(nanoseconds + delay); int64_t boundTimeInterval = timeInterval >= 0 ? timeInterval : 0; __weak typeof(self) weakSelf = self; NSLog(@"%@ addOperation: %@ intoQueue: %@ withOperationDelayInNanoseconds: %@ boundTimeInterval: %@. operationCount: %@", weakSelf.debugDescription, op, weakSelf.underlyingQueue, @(nanoseconds), @(boundTimeInterval), @(weakSelf.operationCount)); //uderlyingQueue could be nil. //maybe just add operation in queue? //https://github.com/Tricertops/GrandSwiftDispatch/issues/1 //maybe the best why is to remove such a queue :/ if (weakSelf.underlyingQueue == nil) { NSLog(@"%@ underlyingQueue is %@", weakSelf.debugDescription, weakSelf.underlyingQueue); } dispatch_queue_t queue = weakSelf.underlyingQueue ?: dispatch_queue_create("com.myproject.concurrency", NULL); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, boundTimeInterval), queue, ^{ [weakSelf addOperation:op]; }); }It may not work ( not sure how it works. )But in this code I encountered self.unerlyingQueue value nil due to documentation.So, I put adding operation in dispatch_after block and it is fires after delay.This example adds delay only before adding operation. It don't add delay gap between two operations with desired interval.Now I try to figure out how to do it.Subclass from NSOperation.@interface MyProjectDelayedOperation : NSOperation @property (assign, nonatomic, readwrite) NSInteger beforeDelayInSeconds; @property (assign, nonatomic, readwrite) NSInteger afterDelayInSeconds; @end @interface MyProjectDelayedOperation () @property (strong, readwrite) NSOperation *operation; @property (readwrite, getter=isCancelled) BOOL cancelled; @property (readwrite, getter=isExecuting) BOOL executing; @property (readwrite, getter=isFinished) BOOL finished; //@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below //@property (readonly, getter=isAsynchronous) BOOL asynchronous NS_AVAILABLE(10_8, 7_0); @property (readonly, getter=isReady) BOOL ready; @end static const void *observerContextIsCancelled; static const void *observerContextIsFinished; @implementation MyProjectDelayedOperation - (instancetype)initWithOperation:(NSOperation *)operation { if (self = [super init]) { self.operation = operation; [self.operation addObserver:self forKeyPath:@"isCancelled" options:0 context:observerContextIsCancelled]; [self.operation addObserver:self forKeyPath:@"isFinished" options:0 context:observerContextIsFinished]; } return self; } - (void)start { // wait before start for seconds. double delayInSeconds = self.beforeDelayInSeconds; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); __weak __typeof(self)weakSelf = self; dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [weakSelf willChangeValueForKey:@"isExecuting"]; weakSelf.executing = YES && !weakSelf.cancelled; [weakSelf didChangeValueForKey:@"isExecuting"]; if (self.executing && !self.cancelled) { [weakSelf.operation start]; } }); } // subscipt on operation values. - (void)cancel { [self willChangeValueForKey:@"isCancelled"]; self.cancelled = YES; [self didChangeValueForKey:@"isCancelled"]; if (!self.operation.cancelled) { [self.operation cancel]; } } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context { if ((object == self.operation) && (context == observerContextIsCancelled)) { [self cancel]; } else if ((object == self.operation) && (context == observerContextIsFinished)){ [self finished]; } } - (void)finished { // should wait for state "done" double delayInSeconds = self.afterDelayInSeconds; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); __weak __typeof(self)weakSelf = self; dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [weakSelf willChangeValueForKey:@"isExecuting"]; [weakSelf willChangeValueForKey:@"isFinished"]; weakSelf.executing = NO; weakSelf.finished = YES; [weakSelf didChangeValueForKey:@"isFinished"]; [weakSelf didChangeValueForKey:@"isExecuting"]; }); } @endIt wraps operation and adds intervals before start and after finish.It listens underlying operation events isCancelled and isFinished to react on them and to fire delayed operation finish.Not sure how to add before and after delays properly.Of course, this may work with queues maximum concurrent operations value equal one. ( Serial queue )
2
0
2.9k
Feb ’17
Is it possible to build event bus queue with combine publishers and subjects?
I have the following attempt. The main idea is to .receive(on: queue) operator with private queue However, it doesn't work as expected. Is it possible to build event bus queue with combine publishers and subjects? . swift class Work {     var cancellable: AnyCancellable?     var cancellable2: AnyCancellable?     typealias Input = Int     private var inputSubject: PassthroughSubjectInput, Never = .init()     private var inputPublisher: AnyPublisherInput, Never     init() {         let queue: DispatchQueue = .init(label: "com.abc.abc")         self.inputPublisher = self.inputSubject.receive(on: queue).eraseToAnyPublisher()         self.inputSubject     }     func handle(_ input: Input) {         self.inputSubject.send(input)     }     func work() {         let numbers: [Int] = Array(1...10)         self.cancellable2 = self.inputPublisher.sink { (value) in             let count: Int = .random(in: 3...5)             sleep(UInt32(count))             print(value)         }         self.cancellable = numbers.publisher.receive(on: DispatchQueue.global()).sink { [weak self] (value) in             self?.handle(value)         }     } }
0
0
766
Feb ’21
What is a thread with name "uikit datasource diffing"?
I am using Diffable Datasource in an app. I stop app at breakpoint with image loading before dispatch on background thread ( network ). I see a thread with name com.apple.uikit.datasource.diffing. It is a serial thread with number 1 and I suppose it is main thread (stack says so). However, could anybody describe a purpose of this thread and, especially, label name. Maybe it is not a main thread.
0
0
972
Oct ’20
How to properly wrap method to dispatch it on specific queue in Combine?
Consider the following I have a method that call external library Lib. enum Service { &#9;enum Invocation { &#9;&#9;static func findBy(id: String) -> Data? { Lib.FindById(id) } &#9;} } Next, I would like to introduce a Future which wrap this call to be compatible with Combine. extension Service { static func findBy(id: String) -> Future<Data?, Never> { &#9;&#9;&#9;.init { promise in promise(Invocation.findBy(id: id)) } &#9;&#9;} } What is a proper ("Combinish") way to dispatch Invocation.findBy on a given thread/queue? I would like to dispatch this method on background thread, however, it is too expensive if I call it many times. Also if I have many Combine modifiers , the call to this method is delayed, correct? But I would like to dispatch invocation on different queue/thread as soon as possible. .subscribe(on: Scheduler) modifier doesn't change the execution queue/thread of body of future Service.findBy.
0
0
447
Oct ’20
List of compatible devices for each technology
It would be great to know the list of compatible devices for each technology.Many technologies ( ARKit, Metal, Metal 2, VR, CareKit ) and more are not compatible with old devices.And it would be great to see a list with these devices ( or an app? ) which show which technologies you don't have in case of your pretty old device.In thread I ask a question about old devices and new technologies.As I know Metal doesn't support Macbook Pro 2011 and earlier.But macOS High Sierra has Macbook Pro 2010 in compatible devices list.And as I undestand ( not correctly, I suppose ) macOS 10.13 uses Metal 2 under Window server.Is it a contradiction?
2
0
1.1k
Jun ’17
How to embed UITextView in a ContentView if I use UICollectionViewCompositionalLayout.list.
Hello! Description I have a ContentView which contains UITextView. I would like to use this ContentView in UICollectionViewCell. View Hierarchy UICollectionView { &#9;MyContentView { &#9;&#9;UIStackView { &#9;&#9;&#9;UITextView &#9;&#9;} &#9;} } As you see I add additional UIStackView that embraces UITextView. Problem When I typing in UITextView, it doesn't grow at all. But if I press on cell and apply configuration is applied to content view, everything works fine and I get correct size of textView. Code class CustomConfigurationCell: UICollectionViewCell { &#9;&#9;override func updateConfiguration(using state: UICellConfigurationState) { &#9;&#9;&#9;&#9;super.updateConfiguration(using: state) &#9;&#9;&#9;&#9;backgroundConfiguration = CustomBackgroundConfiguration.configuration(for: state) &#9;&#9;} } class MyContentView { &#9;&#9;private var appliedConfiguration: CustomContentConfiguration! &#9;&#9; &#9;&#9;private func apply(configuration: CustomContentConfiguration) { &#9;&#9;&#9;&#9;guard appliedConfiguration != configuration else { return } &#9;&#9;&#9;&#9;appliedConfiguration = configuration &#9;&#9;} } What have I tried so far? I added listeners for textViewDidChange and call all setNeedsUpdateConstraints, setNeedsLayout and other layout methods on both self ( ContentView ) and self.superview ( CustomConfigurationCell ).
2
0
906
Sep ’20
How should I use UIConfigurationStateCustomKey?
Hi! Beginning I would like to know about UIConfigurationStateCustomKey. Documentation In a documentation we can find example where CellConfiguration has been extended and later CustomCell subclass get a property to update cell if needed. A part of documentation: // Declare a custom key for a custom isArchived state. extension UIConfigurationStateCustomKey { &#9;&#9;static let isArchived = UIConfigurationStateCustomKey("com.my-app.MyCell.isArchived") } // Declare an extension on the cell state structure to provide a typed property for this custom state. extension UICellConfigurationState { &#9;&#9;var isArchived: Bool { &#9;&#9;&#9;&#9;get { return self[.isArchived] as? Bool ?? false } &#9;&#9;&#9;&#9;set { self[.isArchived] = newValue } &#9;&#9;} } class MyCell: UICollectionViewCell { &#9;&#9;// This is an existing custom property of the cell. &#9;&#9;var isArchived: Bool { &#9;&#9;&#9;&#9;didSet { &#9;&#9;&#9;&#9;&#9;&#9;// Ensure that an update is performed whenever this property changes. &#9;&#9;&#9;&#9;&#9;&#9;if oldValue != isArchived { &#9;&#9;&#9;&#9;&#9;&#9;&#9;&#9;setNeedsUpdateConfiguration() &#9;&#9;&#9;&#9;&#9;&#9;} &#9;&#9;&#9;&#9;} &#9;&#9;} } Documentation example Look at it carefully. We define custom key and, later, add stored property to ConfigurationState. But! We also define a property for MyCell, which has didSet hook with setNeedsUpdateConfiguration invocation. How do I understand this pattern? We define a custom property that could be stored in cell configuration. Later, that property can be changed by a user. So, whenever something happened ( user press a button? ), this cell object receives obj.isArchived = valueFromUser. But! If we use this approach, we also define UIContentConfiguration with our UIContentView. That means, that we have our CustomUIContentView: UIContentView with all buttons that we need. These buttons change state of an associated model object. So, we define Row with all booleans which are related/mapped to buttons on CustomUIContentView. Conclusion There is no point where we should use properties for Cells. Question Am I missing something with new API?
1
0
947
Sep ’20
[UITableViewDiffableDataSource] How to embed UITextView in UITableViewCell with UITableView.automaticDimension for cell height.
The problem:1. You have UITableView with UITableView.automaticDimension for cell height.2. You have a simple cell, that embed UITextView into .contentView.3. UITextView, of course, disables its scroll.Question:How to expand/change cell size by using only UITableViewDiffableDataSource?Actual:In documentation object (MyViewModel) that represents view model for a corresponding cell, should conform to Hashable protocol. It is done for "diffing" on "Array" concept level ( operations as Insert and Delete ).How to react on update operations in this case?NOT a solution:I found in a blog postthat I have to call tableView.begin/end updates on text did changed.It is a hack.However, it works as expected and I would like to hear different solutions and appropriate patterns about Diffable datasource.Thanks!
1
0
1.6k
Feb ’20
How to properly implement single update for a single cell with identifier?
Consider, that you have a struct that represents a Row. struct Row { &#9;var diffable: AnyHashable &#9;var yourDataProviderForCell: Provider } struct ListViewModel { &#9;var providers: [Provider] { didSet { self.rows = rowsFromProviders(self.providers) } } &#9;@Published var rows: [Row] } So, it is simple, you have a list of providers that store all required information for cell. You encapsulate everything in ListViewModel, so, you could add this ListViewModel to your ViewController, right? class ListViewController { &#9;var viewModel: ListViewModel &#9;func configured() { &#9;&#9;self.viewModel.$rows { &#9;&#9;&#9;// Apply snapshot. &#9;&#9;} &#9;} } Everything will ok fine when you add required protocols to Row: extension Row: Hashable { &#9;func == (lhs: Self, rhs: Self) { &#9;&#9;lhs.diffable == rhs.diffable &#9;} &#9;func hash(inout hasher: Hasher) { &#9;&#9;hasher.combine(self.diffable) &#9;} } Look at what we have now. - ListViewController subscribed on @Published rows ListViewModel updates var providers and in didSet we update rows. Row has var diffable: AnyHashable which encapsulates unique nature of Row. ( So, it should be unique, but it contains various information from Provider ) And it will work fine after we add following initializer. extension Row { &#9;init(provider: Provider) { &#9;&#9;self.provider = provider &#9;&#9;self.diffable = Provider.DiffableBuilder(provider) &#9;} } We add Provider.DiffableBuilder which will build AnyHashable key for Row that will be used in Equatable and Hashable for Row and will determine if cell is changed or not. The technique above describes one possible solution to update cells. We simply store a snapshot or a piece of cell data that will be determined as unique set. In this circumstances we could do nothing and just apply updates via append items without reload cells. Is it a good technique and should it be banned or not?
0
0
524
Jun ’20
What is LOCAL_LIBRARY_DIR and how does it work?
Hi!We have a discussion about where we should put our in-house framework.At first we try ./Library folder.Our framework doesn't have Info.plist file and it is generated from Go source.Cmd + B was successful, but Running app in simulator ends with following error:This app could not be installed at this time. Could not install at this time. Failed to load Info.plist from bundle at path .../CoreSimulator/Devices/8C671053-E54B-44D5-A9BC-966D45C0A5B1/data/Libst: ACL=After googling and inspecting git diff, I've found interesting change:FRAMEWORK_SEARCH_PATH contains $(PROJECT_DIR)$(LOCAL_LIBRARY_DIR)SolutionChanging this setting FRAMEWORK_SEARCH_PATH to $(PROJECT_DIR)/Library.ObservationI inspect this variable in xcodebuild:xcodebuild -showBuildSettings | grep LOCAL_LIB LOCAL_LIBRARY_DIR = /LibraryQuestionCould anybody tell what is going on and why Xcode treat local folder "./Library" in this special case?
1
0
1.1k
Feb ’20