Q: In Machine learning, What is the best way to encode non hierarchic categorial features? For String features when the order doesn't matter, what is better get dummies or oneHotEncoder? 
For example, on this pandas data frame: 
df_with_cat = pd.DataFrame({'A': ['ios', 'android', 'web', 'NaN', 'ios','ios', 'NaN', 'android'], 'B' : [4, 4, 'NaN', 2, 'NaN', 3, 3, 'NaN']})

df_with_cat.head()

    A        B
---------------
0   ios      4
1   android  4
2   web      NaN
3   NaN      2
4   ios      NaN
5   ios      3
6   NaN      3
7   android  NaN

I know that now in order to handle them (Impute the missing values etc.) I have to encode them, something like this:
from sklearn.preprocessing import LabelEncoder

df_with_cat_orig = df_with_cat.copy()
la_encoder = LabelEncoder()
df_with_cat['A'] = la_encoder.fit_transform(df_with_cat.A)

Output:
df_with_cat.head(10)

    A   B
-----------
0   2   4
1   1   4
2   3   NaN
3   0   2
4   2   NaN
5   2   3
6   0   3
7   1   NaN

But now it seems like there is some order 0-3 but this is not the case... 'ios' ->2 is not necessarily greater than 'android' ->1

A: Categorical features are different from numerical features in that categorical features are a set of discrete values while numerical features form a continuous sequence. For example 
for feature "animal" if 1 -> cat, and 2 -> dog, you can't have a 1.5, you're either 1 or 2. And in this setup dog isn't necessarily greater than cat - the one and two are merely encodings of the "real" feature.  
On the other hand for feature "price", you've got a large range of possible values, and there's a clear definition on what values are greater than other values.
In terms of dealing with categorical features, you're spot on - we encode them. For example sklearn.preprocessing has an OrdinalEncoder which just transforms categorical features (mainly strings like "male", "female", etc.) into integers.
Now I'm not too familiar with sklearn and what kinds of encodings it takes but I feel I should discuss some more "advanced" ways to encode categorical features. Depending on what machine learning models you use these may or not apply. Personally I primarily use these with neural networks.
The simpler one is a one-hot-encoding, which is similar to your default of encoding each category to an integer. Except this time to get rid of the problem where the model treats one category as greater than another, it uses an array of ones and zeros. i.e. "cat" -> 0 -> [1, 0, 0], "dog" -> 1-> [0, 1, 0], "bird" -> 2 -> [0, 0, 1]. Essentially each category is encoded to an integer index, and your result is an array of all zeros except a one at that index.
Another way we encode is using Embeddings. It's very similar to a one-hot-encoding in that you're converting an integer index (for a category) into an n-dimensional vector. However it saves space in that the size of the vector can be less than the number of categories. This is commonly used in neural networks that process semantic information. Each word is passed into the model as an integer index, but an Embedding layer converts each index into an n-dimensional vector. As you train the model the Embedding layer gets better and better representations of each category.

A: I just got an answer to my question above (and related to the yellow marked below):
When you encode them to numbers and leave them all as a single feature, the model is assuming that the order means something, for that matter that 'ios' (which is mapped to 2) is greater than 'android' (which is equal to 1)

But now it seems like there is some order 0-3 but this is not the
  case... 'ios' ->2 is not necessarily greater than 'android' ->1

If for the specific feature there are not too many categories it's easy to use on them get dummies:
data_with_dummies = pd.get_dummies(df_with_cat, columns=['A'], drop_first=True)


        B A_1 A_2   A_3
------------------------
    0   4   0   1   0
    1   4   1   0   0
    2   NaN 0   0   1
    3   2   0   0   0
    4   NaN 0   1   0
    5   3   0   1   0
    6   3   0   0   0
    7   NaN 1   0   

Now we are avoiding the problem I stated to begin with, this should improve the model's performance significantly 
Or just use OneHotEncoder - as @Primusa stated in the answer above

A: All you just need is OneHotEncoder
from sklearn.preprocessing import LabelEncoder

df_with_cat_orig = df_with_cat.copy()
la_encoder = LabelEncoder()
df_with_cat['A'] = la_encoder.fit_transform(df_with_cat.A)

from sklearn.preprocessing import OneHotEncoder

oh_enc = OneHotEncoder(categorical_features=[0])
df_with_cat = oh_enc.fit_transform(df_with_cat).toarray()

df_with_cat = df_with_cat[:, 1:]       # remove first column to avoid dummy variable trap

