Ошибка «NSCFArray мутировал при перечислении» при перечислении копии - PullRequest
0 голосов
/ 08 февраля 2012
def leopardRemoveWireless(networkName):
  plistPath = '/Library/Preferences/SystemConfiguration/preferences.plist'
  # Sanity checks for the plist
  if os.path.exists(plistPath):
    try:
      pl = NSMutableDictionary.dictionaryWithContentsOfFile_(plistPath)
    except:
      print 'Unable to parse file at path: %s' % plistPath
      sys.exit(1)
  else:
    print 'File does not exist at path: %s' % plistPath
    sys.exit(1)
  # Create a copy of the dictionary due to emuration
  copy = NSDictionary.dictionaryWithDictionary_(pl)
  # Iterate through network sets
  for Set in copy['Sets']:
    UserDefinedName = copy['Sets'][Set]['UserDefinedName']
    print 'Processing location: %s' % UserDefinedName

    for enX in copy['Sets'][Set]['Network']['Interface']:
      print 'Processing interface: %s' % enX
      # I think this will always be a single key but this works either way
      for key in copy['Sets'][Set]['Network']['Interface'][enX]:
        print 'Processing Service: %s' % key
        # Try to grab the PreferredNetworks key if any
        try:
          # Iterate through preferred network sets
          index = 0
          for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:
            SSID_STR = PreferredNetwork['SSID_STR']
            print 'Processing SSID: %s' % SSID_STR
            # If the preferred network matches our removal SSID
            if SSID_STR == networkName:
              print 'Found SSID %s to remove' % SSID_STR
              # Delete our in ram copy
              print 'Processing Set: %s' % Set
              print 'Processing enX: %s' % enX
              print 'Processing key: %s' % key
              del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]
            index += 1
        except KeyError:
           print 'Skipping interface without PreferredNetworks'

Я редактирую довольно сложный (словарный) список и затем записываю изменения обратно в файл после того, как найду конкретную пару ключ-значение.Проблема в том, что, хотя я делаю копию словаря списков свойств:

copy = NSDictionary.dictionaryWithDictionary_(pl)

Это дает мне стандартную ошибку "мутировал при перечислении", когда я редактирую оригинал, только ключи цикла в качестве стендаins (обратите внимание на отсутствие кавычек).

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

Мой синтаксис как-то заставляет его пытаться редактировать словарь pl, а не copy?Вот вывод:

... Набор обработки: D5C0A0F4-613A-4121-B6AE-4CBA6E2635FF Обработка enX: en1 Ключ обработки: трассировка AirPort (последний вызов последнего): Файл "/ Users /tester / Desktop / wifiutil ", строка 1164, в файле sys.exit (main ())" / Users / tester / Desktop / wifiutil ", строка 1135, в главном файле removeWireless (osVersion, network)" / Users / tester / Desktop/ wifiutil ", строка 1051, в removeWireless leopardRemoveWireless (network)
Файл" / Users / tester / Desktop / wifiutil ", строка 528, в leopardRemoveWireless для PreferredNetwork в копии ['Sets'] [Set] ['Network']['Interface'] [enX] [key] ['PreferredNetworks']: Файл "/System/Library/Frameworks/Python.framework/Versions/2.5/Extras/lib/python/PyObjC/objc/_convenience.py", строка431, в enumeratorGenerator выдает container_unwrap (anEnumerator.nextObject (), StopIteration) objc.error: NSGenericException - * Коллекция была видоизменена при перечислении.

1 Ответ

1 голос
/ 08 февраля 2012

Я считаю, что проблема заключается во вложенности словаря. dictionaryWithDictionary_() не делает ничего похожего на глубокую копию; все, что он делает, это создает новый NSDictionary и копирует указатели для значений (он сам копирует ключи, поскольку это характер NSDictionary).

Это означает, что, хотя у вас есть новый верхний уровень, который вы можете использовать для перечисления, внутренние словари и массивы являются точно такими же объектами, как и в оригинале.

Ваш последний цикл:

for PreferredNetwork in copy['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks']:

перечисляет один из тех внутренних массивов, которые вы затем пытаетесь изменить с помощью оператора del:

del pl['Sets'][Set]['Network']['Interface'][enX][key]['PreferredNetworks'][index]

Это не было скопировано; это тот же объект массива, который вы используете в for, что вызывает исключение. Вы можете проверить это, передав два выражения в id().

Вам придется либо сделать полную копию исходного словаря, либо (возможно, лучше) сделать копию последнего уровня, прежде чем перечислять его.

...