One can argue that automatic reference counting is a form of garbage collection. It is, however, deterministic and that’s why some engineers tend to prefer it.
It is not deterministic in the presence of deep nested data structures like acyclic graphs, where the amount of time running cascading deletes canny be fully calculated. Likewise the amount of stack space cannot be fully determined. Finally, sharing pointers across threads introduces non-deterministic cache locks and delays.
Herb Sutter has a quite good CppCon talk about it.
Many engineers prefer it due to cargo cult and anti-tracing GC bias, despite years of CS papers proving the contrary since the early 80's.
It is deterministic wrt. the object lifetime which is exactly what you need if your "delete" is actually controlling access to some shared resource that must be freed promptly when it goes out of use. The drawbacks you mentioned are largely-unavoidable consequences of that requirement, and they mostly matter when the allocation graph is large and complex. It's why obligate RC as found in Swift is likely a bad idea, and even inferior to obligate tracing GC - but other languages can do better than that, e.g. introducing arenas that can be used to allocate or free objects as a group, in a single operation.
Plenty of tracing GC also offer the same control over arenas and deterministic destruction, one just needs to actually use them, e.g. D, Modula-3, Mesa/Cedar, Active Oberon, Eiffel, System C#, C# 7.3/8...