Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (C) 2012 RoboVM AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.robovm.objc;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.robovm.objc.annotation.NativeClass;
import org.robovm.objc.annotation.Property;
import org.robovm.rt.VM;
import org.robovm.rt.bro.NativeObject;
import org.robovm.rt.bro.Struct;
import org.robovm.rt.bro.annotation.Callback;
import org.robovm.rt.bro.annotation.Library;
import org.robovm.rt.bro.annotation.Marshaler;
import org.robovm.rt.bro.annotation.Marshalers;
import org.robovm.rt.bro.annotation.MarshalsPointer;
import org.robovm.rt.bro.annotation.Pointer;
import org.robovm.rt.bro.annotation.StructMember;
import org.robovm.rt.bro.ptr.Ptr;
import org.robovm.rt.bro.ptr.VoidPtr;
/**
*
*/
@Library("Foundation")
@NativeClass("Object")
@Marshalers({
@Marshaler(ObjCObject.Marshaler.class),
@Marshaler(ObjCClass.Marshaler.class)
})
public abstract class ObjCObject extends NativeObject {
private static volatile boolean logRetainRelease = false;
public static class ObjCObjectPtr extends Ptr {}
static {
ObjCRuntime.bind(ObjCObject.class);
try {
Field f = ObjCObject.class.getDeclaredField("customClass");
CUSTOM_CLASS_OFFSET = VM.getInstanceFieldOffset(VM.getFieldAddress(f));
} catch (Throwable t) {
throw new Error(t);
}
NS_OBJECT_CLASS = ObjCRuntime.objc_getClass(VM.getStringUTFChars("NSObject"));
}
/**
* Common lock object used to prevent concurrent access to data in the Obj-C
* bridge (such as {@link ObjCObject#peers} and
* {@link ObjCClass#typeToClass}). This should be used to prevent deadlock
* situations from occurring. (#349)
*/
static final Object objcBridgeLock = new Object();
private static final LongMap peers = new LongMap<>();
private static final long CUSTOM_CLASS_OFFSET;
private static final long NS_OBJECT_CLASS;
private ObjCSuper zuper;
protected final boolean customClass;
protected ObjCObject() {
long handle = alloc();
setHandle(handle);
if (handle != 0) {
// Make sure the peer is set immediately even if a different handle
// is set later with initObject().
setPeerObject(handle, this);
}
customClass = getObjCClass().isCustom();
}
protected ObjCObject(long handle) {
initObject(handle);
customClass = getObjCClass().isCustom();
}
ObjCObject(long handle, boolean customClass) {
initObject(handle);
this.customClass = customClass;
}
protected void initObject(long handle) {
if (handle == 0) {
throw new RuntimeException("Objective-C initialization method returned nil");
}
long oldHandle = getHandle();
if (handle != oldHandle) {
if (oldHandle != 0) {
removePeerObject(this);
}
setHandle(handle);
setPeerObject(handle, this);
}
}
protected long alloc() {
throw new UnsupportedOperationException("Cannot create instances of " + getClass().getName());
}
@Override
protected final void finalize() throws Throwable {
dispose(true);
}
public final void dispose() {
dispose(false);
}
protected void doDispose() {}
protected void dispose(boolean finalizing) {
long handle = getHandle();
if (handle != 0) {
removePeerObject(this);
doDispose();
setHandle(0);
}
if (finalizing) {
try {
super.finalize();
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
}
@SuppressWarnings("unchecked")
protected ObjCSuper getSuper() {
if (zuper == null) {
Class extends ObjCObject> javaClass = (Class extends ObjCObject>) getClass().getSuperclass();
ObjCClass objCClass = ObjCClass.getByType(javaClass);
while (objCClass.isCustom()) {
javaClass = (Class extends ObjCObject>) javaClass.getSuperclass();
objCClass = ObjCClass.getByType(javaClass);
}
zuper = new ObjCSuper(this, objCClass);
}
return zuper;
}
protected void afterMarshaled(int flags) {}
public final ObjCClass getObjCClass() {
return ObjCClass.getFromObject(this);
}
@SuppressWarnings("unchecked")
protected static T getPeerObject(long handle) {
synchronized (objcBridgeLock) {
ObjCObjectRef ref = peers.get(handle);
T o = ref != null ? (T) ref.get() : null;
return o;
}
}
/**
* this notification callback from callback for custom object.
* It is called to save corresponding java part in ObjectOwnershipHelper
* as it is the only place that keeps custom object from GC while native part is
* retained
* @param handle of native object
*/
protected static void retainCustomObjectFromCb(long handle) {
ObjectOwnershipHelper.retainObject(handle);
}
private static void setPeerObject(long handle, ObjCObject o) {
synchronized (objcBridgeLock) {
if (o == null) {
peers.remove(handle);
} else {
peers.put(handle, new ObjCObjectRef(o));
}
}
}
private static void removePeerObject(ObjCObject o) {
synchronized (objcBridgeLock) {
long handle = o.getHandle();
ObjCObjectRef ref = peers.remove(handle);
ObjCObject p = ref != null ? ref.get() : null;
if (p != null && o != p) {
// Not the same peer. Put it back.
peers.put(handle, new ObjCObjectRef(p));
}
}
}
public T addStrongRef(T to) {
AssociatedObjectHelper.addStrongRef(this, to);
return to;
}
public void removeStrongRef(Object to) {
AssociatedObjectHelper.removeStrongRef(this, to, false);
}
/**
* Updates a strong reference handling {@code null} values properly. This is
* meant to be used for {@link Property} setter methods with
* {@code strongRef=true}.
*
* @param before the previous value for the property. If not {@code null}
* and not equal to {@code after}
* {@link #removeStrongRef(Object)} will be called on this value.
* @param after the new value for the property. If not {@code null} and not
* equal to {@code after} {@link #addStrongRef(Object)} will be
* called on this value.
*/
public void updateStrongRef(Object before, Object after) {
if (before == after) {
// Either both are null or they reference the same object.
// If not null we assume that the property has already been set so
// that there already exists a strong reference.
return;
}
if (before != null) {
// Don't fail if the before value didn't have a strong reference.
// It could have been set from within ObjC.
AssociatedObjectHelper.removeStrongRef(this, before, true);
}
if (after != null) {
AssociatedObjectHelper.addStrongRef(this, after);
}
}
public Object getAssociatedObject(Object key) {
return AssociatedObjectHelper.getAssociatedObject(this, key);
}
public void setAssociatedObject(Object key, Object value) {
AssociatedObjectHelper.setAssociatedObject(this, key, value);
}
public static T toObjCObject(Class cls, long handle, int afterMarshaledFlags) {
return toObjCObject(cls, handle, afterMarshaledFlags, false);
}
@SuppressWarnings("unchecked")
public static T toObjCObject(Class cls, long handle, int afterMarshaledFlags, boolean forceType) {
if (handle == 0L) {
return null;
}
if (cls == ObjCClass.class) {
return (T) ObjCClass.toObjCClass(handle);
}
if (forceType) {
/*
* Always return a new instance without making it the new peer.
*/
return createInstance(ObjCClass.getByType(cls), handle, afterMarshaledFlags, false);
}
/*
* Determine the expected return type. Usually cls but it cls is an
* ObjCProxy class the expected type is instead the proxied interface.
*/
Class> expectedType = cls;
if (ObjCClass.isObjCProxy(cls)) {
expectedType = cls.getInterfaces()[0];
}
synchronized (objcBridgeLock) {
T o = getPeerObject(handle);
if (o != null && o.getHandle() != 0) {
if (!expectedType.isAssignableFrom(o.getClass())) {
if (ObjCClass.isObjCProxy(o.getClass())) {
/*
* The current peer is an incompatible ObjCProxy.
* Override that peer with a new one of the correct
* type.
*/
removePeerObject(o);
o = null;
} else if (ObjCClass.isObjCProxy(cls)) {
/*
* The current peer is not an ObjCProxy but we're
* expected to return one. Just return a new instance of
* the proxy without making it the peer.
*/
return createInstance(ObjCClass.getByType(cls), handle, afterMarshaledFlags, false);
} else {
/*
* Neither is an ObjCProxy. The current peer MUST be an
* instance of the expected type.
*/
throw new IllegalStateException("The peer object type " + o.getClass().getName()
+ " is not compatible with the expected type " + expectedType.getName());
}
} else {
return o;
}
}
ObjCClass objCClass = ObjCClass.getFromObject(handle);
if (!expectedType.isAssignableFrom(objCClass.getType())) {
/*
* If the expected return type is incompatible with the type of
* the native instance we have to make sure we return an
* instance of the expected type. See issue #821.
*/
objCClass = ObjCClass.getByType(cls);
}
return createInstance(objCClass, handle, afterMarshaledFlags, true);
}
}
/**
* Creates a new instance of the specified {@link ObjCClass}. If
* {@code makePeer == true} this method MUST be called while the
* {@link #objcBridgeLock} is held.
*/
@SuppressWarnings("unchecked")
private static T createInstance(ObjCClass objCClass, long handle, int afterMarshaledFlags,
boolean makePeer) {
Class c = (Class) objCClass.getType();
T o = VM.allocateObject(c);
o.setHandle(handle);
if (makePeer) {
setPeerObject(handle, o);
}
if (objCClass.isCustom()) {
VM.setBoolean(VM.getObjectAddress(o) + CUSTOM_CLASS_OFFSET, true);
}
o.afterMarshaled(afterMarshaledFlags);
return o;
}
public static class Marshaler {
@MarshalsPointer
public static ObjCObject toObject(Class extends ObjCObject> cls, long handle, long flags) {
ObjCObject o = ObjCObject.toObjCObject(cls, handle, 0);
return o;
}
@MarshalsPointer
public static long toNative(ObjCObject o, long flags) {
if (o == null) {
return 0L;
}
return o.getHandle();
}
@MarshalsPointer
public static ObjCProtocol protocolToObject(Class> cls, long handle, long flags) {
Class extends ObjCObject> proxyClass = ObjCClass.allObjCProxyClasses.get(cls.getName());
if (proxyClass == null) {
proxyClass = ObjCObject.class;
}
ObjCObject o = ObjCObject.toObjCObject(proxyClass, handle, 0);
return (ObjCProtocol) o;
}
@MarshalsPointer
public static long protocolToNative(ObjCProtocol o, long flags) {
if (o == null) {
return 0L;
}
return ((ObjCObject) o).getHandle();
}
}
static class ObjCObjectRef extends WeakReference {
public final long handle;
public ObjCObjectRef(ObjCObject referent) {
super(referent);
handle = referent.getHandle();
}
}
static class ObjectOwnershipHelper {
private static final LongMap