Apologies if this is too vague... this is my first post here and I'm well and truly stumped on this issue!
I've been attempting to transition an iOS Xcode project using Audio Units to ARC, but it appears to have broken the functionality of the audio unit processing class. Some symptoms... When I attempt referencing 'self' in AUProcessor.mm, the AUProcessor class is referred to as 'const*', whereas in the pre-ARC version, there was no 'const*' mentioned.
This pointer to 'self' produces the following error:
callbackStruct.inputProcRefCon = self;
[error] Assigning to 'void *' from incompatible type 'AUProcessor *const __strong'.
I can remove the error by adding (__bridge void*) ahead of self, which allows the project to compile. However, the Audio Unit processor doesn't work in the app.
I can't see anything elsewhere in the code that is significantly different from the pre-ARC version in terms of how the class is referenced.
Let me know if more context is required.
Thanks in advance!!
(BTW, thank you to all contributors to these forums... they are truly a wonderful resource for keen yet inexperienced programmers!)
Typically, (__bridge void*) would be the correct cast here. This means "take a pointer to this object without applying any memory management; I promise I'll hold onto it for as long as it's needed." (That last part is just implied, but if you don't, you'll crash.)
Are you certain that self continues to exist for as long as this audio unit? If nothing has a strong reference to self, then it will disappear and inputProcRefCon will become a dangling pointer.
When you say "doesn't work in the app," what do you mean? Does it crash? Does the callback not happen? When the callback happens, does it not have the right data?
I managed to resolve my issue by excluding the troublesome class from ARC using the compiler flag -fno-objc-arc.
Its not a very satisfying conclusion but at least my app is working again... Looks like I'm going to need to learn more about memory management!
The code below is working for me with the MusicPlayer API. I don't know that it is correct but I am not getting any errors or memory leaks. Hope it helps!
// assign the callback:
MusicSequenceSetUserCallback( sequence, MyEventCallback, (__bridge_retained void *)self );
//the callback method:
void MyEventCallback(void *inClientData,
MusicSequence inSequence,
MusicTrack inTrack,
MusicTimeStamp inEventTime,
const MusicEventUserData *inEventData,
MusicTimeStamp inStartSliceBeat,
MusicTimeStamp inEndSliceBeat)
{
struct MyMusicEventUserData* userEventData = ( MyMusicEventUserData *)inEventData;
[(__bridge MusicPlayerController*)inClientData MIDIEvent:userEventData
eventTime:inEventTime
startSliceBeat:inStartSliceBeat
endSliceBeat:inEndSliceBeat];
}
Related
The get function below looks to me like it returns a slice referring to data in an array that will be out of scope once the function returns, and therefore is in error. Assuming this is true, is there any way to detect this at compile time or even run time in a debug mode?
I couldn't find any compiler flags that detected this error at compile time or run time and wondered if I'd missed anything that could help or this is just not something zig can detect at this time, which is fine, I'll just have to be more careful :)
This is a cut down example of a real issue I had which took some time to diagnose to demonstrate the problem
const std = #import("std");
fn get() []u8 {
var data : [100]u8 = undefined;
return data[0..99];
}
pub fn main() !void {
const data = get();
std.debug.print("Name: [{}]\n", .{data});
}
I believe that's behaviour that's not currently frowned upon by the compiler (0.6.0 at the time of writing), based on my understanding of the Lifetime and Ownership part of the docs:
It is the Zig programmer's responsibility to ensure that a pointer is
not accessed when the memory pointed to is no longer available. Note
that a slice is a form of pointer, in that it references other memory.
Although it might be addressed with this issue which describes similar behaviour: https://github.com/ziglang/zig/issues/5725
I'm following an apple document, but unfortunately the examples are written on objective-c, but I have confidence with Swift language and can not understand the meaning of some things, in particular, in this example:
void RunLoopSourcesPerformRoutine (void *info){
RunLoopSource* obj = (RunLoopSource*)info;
[obj sourceFired];
}
this line: RunLoopSource* obj = (RunLoopSource*)info;
the parameter: void *info indicates that info is a pointer to void, then I can put the address of any type of data structure, following various apple documents I saw that the translation of this : void *info into swift language is :
info: UnsafeMutableRawPointer?
Now, the RunLoopSource* obj = (RunLoopSource*)info; line indicates that obj is a variable of type: RunLoopSource, and to this is assigned the value of (RunLoopSource *) info, but precisely What does it mean this statement? : (RunLoopSource *) info, and how it translates in swift language ?
Swift really hates pointer. These 2 lines of code can be converted to Swift as
func RunLoopSourcesPerformRoutine(info: UnsafeMutableRawPointer) {
let obj = info.assumingMemoryBound(to: RunLoopSource.self)
obj.pointee.sourceFired()
}
This specific expression is a "typecast": it's saying that info, which is declared to be a pointer-to-unknown-anything (void *) is actually known by the programmer to be a pointer to a RunLoopSource. This forcibly changes the type of the expression to make the compiler happy as it is assigned to obj.
It is equivalent to using as! in Swift and is idiomatic when you know the semantics of a void * but the syntax doesn't capture it.
(This attempts to answer your question as stated but I'm not sure if you are looking for more information. If so, please clarify and me or someone more expert in unsafe pointers in Swift can help out.)
What you are dealing with (void *info) is a C pointer-to-void, which arrives into Swift as a form of UnsafeRawPointer. This means that type info has been cast away and that memory is being managed elsewhere.
In order to work with this thing as what you believe it to be, i.e. a RunLoopSource, you need to characterize it explicitly as a RunLoopSource. In C, you would cast, as in the example code you posted: (RunLoopSource*)info. In Swift, you rebind.
Observe that in your case this whole thing has been made just a little more complicated by the fact that this UnsafeMutableRawPointer has been wrapped in an Optional, and will have to be unwrapped before you can do anything at all.
Assuming, then, in your case, that info is really an UnsafeMutableRawPointer? bound to a RunLoopSource, you can say:
let rlsptr = info!.assumingMemoryBound(to: RunLoopSource.self)
let rls = rlsptr.pointee
Now rls is a RunLoopSource and you can work with it however you like. Keep in mind, however, that the memory is unmanaged, so you should work with it only here and now.
EDIT By the way, Apple has a really nice document on this entire matter: https://swift.org/migration-guide/se-0107-migrate.html
I heard that Objective-C is influenced by the "message passing mechanism" of SmallTalk.
Objective-C, like Smalltalk, can use dynamic typing: an object can be
sent a message that is not specified in its interface. This can allow
for increased flexibility, as it allows an object to "capture" a
message and send the message to a different object that can respond to
the message appropriately, or likewise send the message on to another
object.
And I felt for codes like [anObject someMethod], the binding of someMethod to the machine code may happen at run-time..
Therefore, I write a demo like this:
#import <Foundation/Foundation.h>
#interface Person : NSObject {
#private char *name;
}
#property (readwrite, assign) char *name;
- (void)sayHello;
#end
#implementation Person
#synthesize name;
- (void)sayHello {
printf("Hello, my name is %s!\n", [self name]);
}
#end
int main() {
Person *brad = [Person new];
brad.name = "Brad Cox";
[brad sayHello];
[brad sayHelloTest];
}
I tried [brad sayHelloTest] to send brad a message sayHelloTest which brad doesn't know how to handle with.. I expect the error will NOT happen at compile-time..
However, the compiler still throws an error:
main.m:24:11: error: instance method '-sayHelloTest' not found (return type defaults to 'id') [-Werror,-Wobjc-method-access]
[brad sayHelloTest];
^~~~~~~~~~~~
main.m:3:12: note: receiver is instance of class declared here
#interface Person : NSObject {
^
Change [(id)brad sayHelloTest] to [(id)brad sayHelloTest]; doesn't work either.. (The compiling command is clang -Wall -Werror -g -v main.m -lobjc -framework Foundation -o main)
In Objective-C, does the binding of method really happen at "run-time"? If so, why will there be a compiler error like this?
If the binding doesn't happen at "run-time", why was "Objective-C" called "dynamic typing language"?
Does anyone have any ideas about this?
One job of a compiler is to catch as many errors at compile time as possible. If it can tell that the call will fail at runtime, you generally want it to complain.
You can suppress this via casting to show that runtime resolution is happening:
[(id)brad sayHelloTest];
Because the IDE can infer the obvious error from the context.
When you write if (a = 1),you will get a warning. A good IDE should help you find mistakes as early as possible.
I figured out the reason finally..
It throw errors during compiling because -Werror flag is included, which will turn warning into error..
http://clang.llvm.org/docs/UsersManual.html#cmdoption-Werror
After I delete -Werror flag, everything works as expected and the error only happens at run-time.
It has become a compiler error only within the last five years for there to be no known declaration of a method. It has to do with Automatic Reference Counting. Under ARC, the compiler is now responsible for the reference-counting-based memory management that Cocoa uses.
Given that responsibilty, it must be able to see the declarations of methods for any messages before they are sent, so that it knows what retains and releases are appropriate.
The method resolution (the lookup of the method on the class) does still happen at runtime, and -- particularly if you disable ARC -- you can still take advantage of message forwarding.
One way around ARC's requirement was given by Marcelo Cantos -- cast the receiver to id. Another is to use performSelector:. A third -- though I can't recommend it -- is to use objc_msgSend() directly.
Note that the "binding" of the method does, and always did, happen at compile time. Methods are associated with classes, when the classes are defined. Messages are distinct from methods, and it is they that resolve at runtime to a method.
The code I have currently functions correctly, however, at present it throws a warning. As the app is to be shipped soon and this particular component is responsible for key functionality I figured it would be worth asking.
The code is as follows (modified slightly):
REC_AppAuthPage *thisView = ((UINavigationController*)self.window.rootViewController).visibleViewController;
[thisView receiveSomeString:someString];
'REC_AppAuthPage' is a UIViewController class.
The warning being thrown is:
"Incompatible pointer types initializing 'REC_AppAuthPage *' with an expression of type 'UIViewController *'"
My question is, is it okay to ignore the warning and release or does something need to be changed? If so what?
Cheers
Add a specific cast to the assignment:
REC_AppAuthPage *thisView = (REC_AppAuthPage *)((UINavigationController*)self.window.
rootViewController).visibleViewController;
I'm trying to use CoreBluetooth's retrievePeripheral :
- (void)retrievePeripherals:(NSArray *)peripheralUUIDs;
The documentation says peripheralUUIDs should be a NSArray of CFUUIDRef. In the Apple sample project temperatureSensor, it is called as :
[centralManager retrievePeripherals:[NSArray arrayWithObject:(id)uuid]];
(uuid being a CFUUIDRef)
When I use the exact same code in XCode 4.5.1, IOS6, I'm getting a error :
Cast of C pointer type 'CFUUIDRef' (aka 'const struct __CFUUID *') to Objective-C pointer type 'id' requires a bridged cast
I would say (though I'm far from sure) that the reason it works in TemperatureSensor and not in my project is because TemperatureSensor seems not to use ARC whereas my project does.
Xcode suggests 2 ways of solving the problem : adding a __bridge or using CFBridgingRelease(). I tried them both and I'm under the impression that the function does not work [Edit] because the delegate methode didRetrievePeripheral: never gets called [/Edit] (my understanding is that these operation would change the C-style structs into objective-C-objects thus creating a NSUUID, and the method can't use it, but, again I'm really not sure)
So what should I do ? I've been searching on google for examples of retrievePeripherals using ARC, but without success.
In the temperature sensor change this line and run
LeDiscovery.m
-(void) startScanningForUUIDString:(NSString *)uuidString
{
[centralManager scanForPeripheralsWithServices:nil options:0];
}
change the word nil and assume 0.
If you want more check this link.
I hope its useful for you.
Turns out the problem was much simpler than that. I copied/pasted some code from TemperatureSensor, specifically the DidRetrievePeripheral. But it turns out, there's an error in this code (it's DidRetrievePeripheralS), so the delegate method never gets called. I think the bug is already reported.
Thanks/sorry