ARC is indeed just a matter of giving every allocation a counter of the number of strong references it has, and deallocating that chunk when it reaches zero.
But nothing says GC must be fancy. A standard tracing garbage collector can be really simple too. All it needs to do is periodically do a recursive tree walk starting from roots and seeing which allocations it can reach, and then destroy all the allocations it can't reach. Different spaces, different generations, and all the rest are enhancements that are added to improve performance, not something fundamental to garbage collection.
Ignoring performance, there are really only two hard parts to creating a garbage collector. You need some function that can return all of the root pointers, and some function that, given a pointer, can give you all of the pointers contained within that object. Given those two things, a competent programmer can write a basic garbage collector in about five minutes.
The only thing that makes ARC possibly "not a garbage collector" (depending on your definitions) is its inability to collect cycles. You can even fix that by tracing references each time you decrement an object's reference count and seeing if it's participating in a cycle with no outside references. This is sort of an inversion of the traditional tracing garbage collector, and can run entirely synchronously, although the scan can also end up looking at all of memory if it's run on something that's highly connected.