[button setFont:...]
устарела.
Используйте вместо этого [button.titleLabel setFont:...]
, например:
[myButton.titleLabel setFont:[UIFont systemFontOfSize:10]];
В многоканальном последовательном COM-сервере каждый экземпляр COM-класса гарантированно доступен для одного потока. Это означает, что экземпляр является потокобезопасным. Однако многие экземпляры могут быть созданы одновременно с использованием разных потоков. Что касается COM-сервера, ваша собственная DLL не должна делать ничего особенного. Подумайте только о kernel32.dll, который используется каждым исполняемым файлом - инициализирует ли он COM, когда используется COM-сервером?
С точки зрения DLL, вы должны быть уверены, что вы поточно-ориентированы, поскольку разные экземпляры могут позвонить вам в то же время. STA не защитит вас в этом случае. Поскольку вы говорите, что не используете какие-либо глобальные переменные, я могу только предположить, что проблема в другом месте, и просто случайно проявляется в обстоятельствах, которые, похоже, указывают на материал COM.
Я подозреваю, что ваша проблема заключалась в том, что где-то глубоко внутри вызываемой DLL она выполнила исходящий вызов COM в другое подразделение (другой поток в том же процессе или объект в MTA или другой процесс полностью). COM разрешает потоку STA, ожидающему результата исходящего вызова, получить другой входящий вызов, обрабатывая его рекурсивно. Он предназначен только для текущих разговоров между одними и теми же объектами - то есть A вызывает B, B вызывает A обратно, A снова вызывает B - но может принимать вызовы от других объектов, если вы передали указатель интерфейса нескольким клиентам или клиенту поделился указателем интерфейса с другим клиентом. Как правило, передавать указатели на интерфейс однопоточного объекта нескольким клиентским потокам - плохая идея, поскольку им нужно будет только ждать друг друга.Создайте один рабочий объект для каждого потока.
COM не может приостанавливать и возобновлять выполнение по желанию в любом потоке - новый входящий вызов в потоке STA может поступить только через насос сообщений. Когда «заблокирован» в ожидании ответа, поток STA фактически перекачивает сообщения, проверяя с помощью фильтра сообщений (см. IMessageFilter), следует ли обрабатывать сообщение. Однако обработчики сообщений не должны делать новый исходящий вызов - если они это сделают, COM вернет ошибку RPC_E_CANTCALLOUT_INEXTERNALCALL («Недопустимо вызывать внутри фильтра сообщений.»)
Подобные проблемы могут возникнуть, если у вас есть насос сообщений ( GetMessage / DispatchMessage) в любом месте собственной библиотеки DLL. У меня были проблемы с DoEvents VB в интерфейсных процедурах.
CoInitializeEx должен вызываться только создателем потока, потому что только он знает, каким будет его поведение перекачки сообщений. Вероятно, что если вы попытаетесь вызвать его в DllMain, он просто потерпит неудачу, поскольку ваша собственная DLL вызывается в ответ на вызов COM, поэтому вызывающий должен в конечном итоге уже вызвать CoInitializeEx в потоке, чтобы сделать вызов. Выполнение этого в уведомлении DLL_THREAD_ATTACH для вновь созданных потоков может работать поверхностно, но может привести к сбою в работе программы, если COM блокируется, когда он должен перекачиваться, и наоборот.