#if is a compile-time condition. The variables are evaluated at compile time, and then whichever branch is taken is the only one investigated. The code in non-taken blocks does not have to compile or type check: it is as though it were not there at all.
@available is an attribute that applies to a subset of Swift declarations, including types, methods, functions, and properties. When used in the way you show above it restricts the availability of the declaration to a specific minimum version on the listed platforms. For non-Apple SDKs this has one major effect: within the scope of the associated declaration the minimum deployment target can be assumed to be the version specified in the availability annotation, not the one used at compile time. This allows that declaration to use newer types, functions, methods, and so-on.
This takes effect at compile time as well. However, unlike with #available, the method must type check and compile. The code will always be emitted into your binary: however, it will only be used when the binary is executed on platforms that meet the availability requirements.
if #available is a run-time version check. At run-time, the condition will be evaluated. If met, code execution will enter the block, otherwise the else case will execute. Like @available, this also has the effect of raising the effective minimum deployment target within the if block to the version specified in the condition. This means that both branches must compile and type-check.